I have a sample class, say Country:
class Country {
public String name;
public int population;
public Flag flag;
...
}
I have this Flag class defined somewhere else
class Flag {
String id;
int pixel;
...
}
Now I create a separate comparator DefaultFlagRankingComparator() that can sort Flag by id. How can I sort a list of Country by Flag id, using this DefaultFlagRankingComparator()?
You can invoke the compare method of the Comparator with the flag field of each country.
DefaultFlagRankingComparator flagComparator =
new DefaultFlagRankingComparator();
Collections.sort(countries, (a, b) ->
flagComparator.compare(a.getFlag(), b.getFlag()));
You could also use Comparator.comparing to create a Comparator using a key extracting function and a Comparator that compares those keys (as suggested by Louis Wasserman).
DefaultFlagRankingComparator flagComparator =
new DefaultFlagRankingComparator();
Collections.sort(countries,
Comparator.comparing(Country::getFlag, flagComparator));
You can compare String values of ids using predefined methods:
Arrays.sort(countries, (c1, c2) -> Objects.compare(
c1.getFlag().getId(), c2.getFlag().getId(),
Comparator.naturalOrder()));
Arrays.sort(countries, Comparator.comparing(country ->
country.getFlag().getId(), Comparator.naturalOrder()));
You can specify a custom Comparator:
Arrays.sort(countries, Comparator
.comparing(country -> country.getFlag(),
new DefaultFlagRankingComparator()));
static class DefaultFlagRankingComparator implements Comparator<Flag> {
#Override
public int compare(Flag o1, Flag o2) {
return Objects.compare(o1.getId(), o2.getId(),
Comparator.naturalOrder());
}
}
You can implement interface Comparable in the Flag class:
Arrays.sort(countries, Comparator.comparing(Country::getFlag));
static class Flag implements Comparable<Flag> {
String id;
public String getId() { return id; }
#Override
public int compareTo(Flag that) {
return Objects.compare(this.getId(), that.getId(),
Comparator.naturalOrder());
}
}
I have a class, person. it has Age, Name, Height, etc.
I am creating a class called PersonCollection which is a wrapper of a list (an ArrayList).
I will like to be able to compare Person objects using the PersonCollection class, Which means, I don't want to make the Person class implement the Comparable interface, I would like the PersonCollection to implement the Comparator interface.
I have having trouble doing that. I have implemented the compare method but still when I compare Person Objects it doesn't work.
for example this code gives me an error (people is an ArrayList
public void insert (Person p){
for(int i = 0; i < people.size(); i++){
if (people.get(i) > p){
//Do something
}
}
}
I know how to use Comparator for sorting, this is different.
I am fully aware of other possible and maybe better solutions (any priority queue class or some sort of sortedset classes)
I wish to do that for ArrayList for a specific reason and I kindly ask you to base your solutions on this instead of suggest other Data structures.
You can write a custom Comparator and use the compare(a, b) method.
https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html#compare-T-T-
Your code would look like
if (myComparator.compare(people.get(i), p) > 0 ) {
According to your description you have a Wrapper class like this?
public class People implements List<Person>, Comparator<Person>{
/* methods */
}
so if you want to really use comparator interface, then you would have to do it like this:
public void insert (Person p){
for(int i = 0; i < people.size(); i++){
if (people.compare(people.get(i),p)){ // because people implements Comparator
//Do something
}
}
}
which should (not too sure though) work.
But i would highly recommend not to use this and think about something better, as a class should not be a comparator and a list (because both interfaces should be used for completly different reasons).
A better approach would be to make Person implement Comparable, and then sort according to that
Below is a piece of code where you can see a custom comparator is making an age comparison on Person object's age attribute.
public class TestCompare {
public static void main(String[] args) {
Person person1 = new Person(45, "Tom");
Person person2 = new Person(12, "Sarah");
Person person3 = new Person(34, "Michael");
Person person4 = new Person(33, "Donald");
Person person5 = new Person(65, "timothy");
List<Person> people = new ArrayList<Person>();
people.add(person1);
people.add(person2);
people.add(person3);
people.add(person4);
people.add(person5);
CustomComparator comparator=new CustomComparator();
for (Person p : people) {
System.out.println(comparator.compare(p, new Person(55, "James")));
}
}
}
class CustomComparator implements Comparator<Person> {
#Override
public int compare(Person o1, Person o2) {
// TODO Auto-generated method stub
return o1.getAge().compareTo(o2.getAge());
}
}
class Person implements Comparable<Person> {
public Person(int age, String name) {
this.age = age;
this.name = name;
}
private Integer age;
private String name;
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public int compareTo(Person o) {
// TODO Auto-generated method stub
return this.getAge().compareTo(o.getAge());
}
}
I have simple class
public class ActiveAlarm {
public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;
}
and List<ActiveAlarm> con. How to sort in ascending order by timeStarted, then by timeEnded? Can anybody help? I know in C++ with generic algorithm and overload operator <, but I am new to Java.
Using Comparator
For Example:
class Score {
private String name;
private List<Integer> scores;
// +accessor methods
}
Collections.sort(scores, new Comparator<Score>() {
public int compare(Score o1, Score o2) {
// compare two instance of `Score` and return `int` as result.
return o2.getScores().get(0).compareTo(o1.getScores().get(0));
}
});
With Java 8 onwards, you can simply use lambda expression to represent Comparator instance.
Collections.sort(scores, (s1, s2) -> { /* compute and return int */ });
Either make ActiveAlarm implement Comparable<ActiveAlarm> or implement Comparator<ActiveAlarm> in a separate class. Then call:
Collections.sort(list);
or
Collections.sort(list, comparator);
In general, it's a good idea to implement Comparable<T> if there's a single "natural" sort order... otherwise (if you happen to want to sort in a particular order, but might equally easily want a different one) it's better to implement Comparator<T>. This particular situation could go either way, to be honest... but I'd probably stick with the more flexible Comparator<T> option.
EDIT: Sample implementation:
public class AlarmByTimesComparer implements Comparator<ActiveAlarm> {
#Override
public int compare(ActiveAlarm x, ActiveAlarm y) {
// TODO: Handle null x or y values
int startComparison = compare(x.timeStarted, y.timeStarted);
return startComparison != 0 ? startComparison
: compare(x.timeEnded, y.timeEnded);
}
// I don't know why this isn't in Long...
private static int compare(long a, long b) {
return a < b ? -1
: a > b ? 1
: 0;
}
}
JAVA 8 and Above Answer (Using Lambda Expressions)
In Java 8, Lambda expressions were introduced to make this even easier! Instead of creating a Comparator() object with all of it's scaffolding, you can simplify it as follows: (Using your object as an example)
Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.timeStarted-a2.timeStarted);
or even shorter:
Collections.sort(list, Comparator.comparingInt(ActiveAlarm ::getterMethod));
That one statement is equivalent to the following:
Collections.sort(list, new Comparator<ActiveAlarm>() {
#Override
public int compare(ActiveAlarm a1, ActiveAlarm a2) {
return a1.timeStarted - a2.timeStarted;
}
});
Think of Lambda expressions as only requiring you to put in the relevant parts of the code: the method signature and what gets returned.
Another part of your question was how to compare against multiple fields. To do that with Lambda expressions, you can use the .thenComparing() function to effectively combine two comparisons into one:
Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.timeStarted-a2.timeStarted
.thenComparing ((ActiveAlarm a1, ActiveAlarm a2) -> a1.timeEnded-a2.timeEnded)
);
The above code will sort the list first by timeStarted, and then by timeEnded (for those records that have the same timeStarted).
One last note: It is easy to compare 'long' or 'int' primitives, you can just subtract one from the other. If you are comparing objects ('Long' or 'String'), I suggest you use their built-in comparison. Example:
Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.name.compareTo(a2.name) );
EDIT: Thanks to Lukas Eder for pointing me to .thenComparing() function.
We can sort the list in one of two ways:
1. Using Comparator : When required to use the sort logic in multiple places
If you want to use the sorting logic in a single place, then you can write an anonymous inner class as follows, or else extract the comparator and use it in multiple places
Collections.sort(arrayList, new Comparator<ActiveAlarm>() {
public int compare(ActiveAlarm o1, ActiveAlarm o2) {
//Sorts by 'TimeStarted' property
return o1.getTimeStarted()<o2.getTimeStarted()?-1:o1.getTimeStarted()>o2.getTimeStarted()?1:doSecodaryOrderSort(o1,o2);
}
//If 'TimeStarted' property is equal sorts by 'TimeEnded' property
public int doSecodaryOrderSort(ActiveAlarm o1,ActiveAlarm o2) {
return o1.getTimeEnded()<o2.getTimeEnded()?-1:o1.getTimeEnded()>o2.getTimeEnded()?1:0;
}
});
We can have null check for the properties, if we could have used 'Long' instead of 'long'.
2. Using Comparable(natural ordering): If sort algorithm always stick to one property:
write a class that implements 'Comparable' and override 'compareTo' method as defined below
class ActiveAlarm implements Comparable<ActiveAlarm>{
public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;
public ActiveAlarm(long timeStarted,long timeEnded) {
this.timeStarted=timeStarted;
this.timeEnded=timeEnded;
}
public long getTimeStarted() {
return timeStarted;
}
public long getTimeEnded() {
return timeEnded;
}
public int compareTo(ActiveAlarm o) {
return timeStarted<o.getTimeStarted()?-1:timeStarted>o.getTimeStarted()?1:doSecodaryOrderSort(o);
}
public int doSecodaryOrderSort(ActiveAlarm o) {
return timeEnded<o.getTimeEnded()?-1:timeEnded>o.getTimeEnded()?1:0;
}
}
call sort method to sort based on natural ordering
Collections.sort(list);
In java8+ this can be written in single line as follows:
collectionObjec.sort(comparator_lamda) or comparator.comparing(CollectionType::getterOfProperty)
code:
ListOfActiveAlarmObj.sort((a,b->a.getTimeStarted().compareTo(b.getTimeStarted())))
or
ListOfActiveAlarmObj.sort(Comparator.comparing(ActiveAlarm::getTimeStarted))
public class ActiveAlarm implements Comparable<ActiveAlarm> {
public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;
public int compareTo(ActiveAlarm a) {
if ( this.timeStarted > a.timeStarted )
return 1;
else if ( this.timeStarted < a.timeStarted )
return -1;
else {
if ( this.timeEnded > a.timeEnded )
return 1;
else
return -1;
}
}
That should give you a rough idea. Once that's done, you can call Collections.sort() on the list.
Since Java8 this can be done even cleaner using a combination of Comparator and Lambda expressions
For Example:
class Student{
private String name;
private List<Score> scores;
// +accessor methods
}
class Score {
private int grade;
// +accessor methods
}
Collections.sort(student.getScores(), Comparator.comparing(Score::getGrade);
Java-8 solution using Stream API:
A. When timeStarted and timeEnded are public (as mentioned in the requirement) and therefore do not (need to) have public getter methods:
List<ActiveAlarm> sorted =
list.stream()
.sorted(Comparator.comparingLong((ActiveAlarm alarm) -> alarm.timeStarted)
.thenComparingLong((ActiveAlarm alarm) -> alarm.timeEnded))
.collect(Collectors.toList());
B. When timeStarted and timeEnded have public getter methods:
List<ActiveAlarm> sorted =
list.stream()
.sorted(Comparator.comparingLong(ActiveAlarm::getTimeStarted)
.thenComparingLong(ActiveAlarm::getTimeEnded))
.collect(Collectors.toList());
If you want to sort the original list itself:
A. When timeStarted and timeEnded are public (as mentioned in the requirement) and therefore do not (need to) have public getter methods:
list.sort(Comparator.comparingLong((ActiveAlarm alarm) -> alarm.timeStarted)
.thenComparingLong((ActiveAlarm alarm) -> alarm.timeEnded));
B. When timeStarted and timeEnded have public getter methods:
list.sort(Comparator.comparingLong(ActiveAlarm::getTimeStarted)
.thenComparingLong(ActiveAlarm::getTimeEnded));
Guava's ComparisonChain:
Collections.sort(list, new Comparator<ActiveAlarm>(){
#Override
public int compare(ActiveAlarm a1, ActiveAlarm a2) {
return ComparisonChain.start()
.compare(a1.timestarted, a2.timestarted)
//...
.compare(a1.timeEnded, a1.timeEnded).result();
}});
We can use the Comparator.comparing() method to sort a list based on an object's property.
class SortTest{
public static void main(String[] args) {
ArrayList<ActiveAlarm> activeAlarms = new ArrayList<>(){{
add(new ActiveAlarm("Alarm 1", 5, 10));
add(new ActiveAlarm("Alarm 2", 2, 12));
add(new ActiveAlarm("Alarm 3", 0, 8));
}};
/* I sort the arraylist here using the getter methods */
activeAlarms.sort(Comparator.comparing(ActiveAlarm::getTimeStarted)
.thenComparing(ActiveAlarm::getTimeEnded));
System.out.println(activeAlarms);
}
}
Note that before doing it, you'll have to define at least the getter methods of the properties you want to base your sort on.
public class ActiveAlarm {
public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;
public ActiveAlarm(String name, long timeStarted, long timeEnded) {
this.name = name;
this.timeStarted = timeStarted;
this.timeEnded = timeEnded;
}
public long getTimeStarted() {
return timeStarted;
}
public long getTimeEnded() {
return timeEnded;
}
#Override
public String toString() {
return name;
}
}
Output:
[Alarm 3, Alarm 2, Alarm 1]
Employee POJO Class
package in.ac.adit.oop.sort;
public class Employee {
private int id;
private String name;
private String department;
public int getId() {
return id;
}
public Employee() {
super();
}
public Employee(int id, String name, String department) {
super();
this.id = id;
this.name = name;
this.department = department;
}
#Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", department=" + department + "]";
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
}
Employee Class To Manage Employee
package in.ac.adit.oop.sort;
import java.util.ArrayList;
import java.util.List;
public class Example {
public static void main(String[] args) {
/*
* Create 10 Employee Object
*/
Employee emp1 = new Employee(1, "Nayan", "IT");
Employee emp2 = new Employee(2, "Siddarth", "CP");
Employee emp3 = new Employee(3, "Samarth", "AE");
Employee emp4 = new Employee(4, "Bhavesh", "CV");
Employee emp5 = new Employee(5, "Sam", "FT");
Employee emp6 = new Employee(6, "Keyur", "IT");
Employee emp7 = new Employee(7, "Bala", "ME");
Employee emp8 = new Employee(8, "Mitul", "ME");
Employee emp9 = new Employee(9, "Kamlesh", "EE");
Employee emp10 = new Employee(10, "Piyush", "EE");
/*
* List of Employee Object
*/
List<Employee> employeeList = new ArrayList<Employee>();
employeeList.add(emp1);
employeeList.add(emp2);
employeeList.add(emp3);
employeeList.add(emp4);
employeeList.add(emp5);
employeeList.add(emp6);
employeeList.add(emp7);
employeeList.add(emp8);
employeeList.add(emp9);
employeeList.add(emp10);
CustomObjectSort customObjectSort = new CustomObjectSort();
List<Employee> sortByDepartment = customObjectSort.sortByDepartment(employeeList);
/*
* Sorted By Department
*/
for (Employee employee : sortByDepartment) {
System.out.println(employee);
}
/*
* Sorted By Name
*/
List<Employee> sortByName = customObjectSort.sortByName(employeeList);
for (Employee employee : sortByName) {
System.out.println(employee);
}
/*
* Sorted By Id
*/
List<Employee> sortById = customObjectSort.sortById(employeeList);
for (Employee employee : sortById) {
System.out.println(employee);
}
}
}
Custom Sorting
package in.ac.adit.oop.sort;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class CustomObjectSort {
public List<Employee> sortByName(List<Employee> employeeList) {
Collections.sort(employeeList, new Comparator<Employee>() {
#Override
public int compare(Employee employee1, Employee employee2) {
return employee1.getName().compareTo(employee2.getName());
}
});
return employeeList;
}
public List<Employee> sortByDepartment(List<Employee> employeeList) {
Collections.sort(employeeList, new Comparator<Employee>() {
#Override
public int compare(Employee employee1, Employee employee2) {
return employee1.getDepartment().compareTo(employee2.getDepartment());
}
});
return employeeList;
}
public List<Employee> sortById(List<Employee> employeeList) {
Collections.sort(employeeList, new Comparator<Employee>() {
#Override
public int compare(Employee employee1, Employee employee2) {
return employee1.getId() - employee2.getId();
}
});
return employeeList;
}
}
You can use Collections.sort and pass your own Comparator<ActiveAlarm>
In java you need to use the static Collections.sort method. Here is an example for a list of CompanyRole objects, sorted first by begin and then by end. You can easily adapt for your own object.
private static void order(List<TextComponent> roles) {
Collections.sort(roles, new Comparator() {
#Override
public int compare(Object o1, Object o2) {
int x1 = ((CompanyRole) o1).getBegin();
int x2 = ((CompanyRole) o2).getBegin();
if (x1 != x2) {
return x1 - x2;
} else {
int y1 = ((CompanyRole) o1).getEnd();
int y2 = ((CompanyRole) o2).getEnd();
return y2 - y1;
}
}
});
}
You can call Collections.sort() and pass in a Comparator which you need to write to compare different properties of the object.
As mentioned you can sort by:
Making your object implement Comparable
Or pass a Comparator to Collections.sort
If you do both, the Comparable will be ignored and Comparator will be used. This helps that the value objects has their own logical Comparable which is most reasonable sort for your value object, while each individual use case has its own implementation.
public class ActiveAlarm {
public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;
}
List<ActiveAlarm> con = new ArrayList<ActiveAlarm>();
Collections.sort(con , (a1, a2) -> a1.timeStarted.compareTo(a2.timeStarted));
Collections.sort(con , (a1, a2) -> a1.timeEnded.compareTo(a2.timeEnded));
Here's what did the trick for me.
Was much shorter and easier than everything else I found:
Collections.sort(listName, Comparator.comparing(Object::getProperty).reversed());
The ".reversed()" part at the end was a requirement for my specific project but I'm sharing it too, as it took a while to find it
The best and the easiest way to sort any list of objects in Java (Java 8 and above).
Lets sort a basket of fruits based on the property "fruitName"
Fruit POJO:
class Fruit
{
int price;
String fruitName;
public Fruit(int price, String fruitName) {
super();
this.price = price;
this.fruitName = fruitName;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getFruitName() {
return fruitName;
}
public void setFruitName(String fruitName) {
this.fruitName = fruitName;
}
#Override
public String toString() {
return "Fruits [price=" + price + ", fruitName=" + fruitName + "]";
}
}
Now lets add fruits into a list and then sort it
List<Fruit> basketOfFruits = new ArrayList<>();
basketOfFruits.add(new Fruit(123, "oranges"));
basketOfFruits.add(new Fruit(45, "nectarine"));
basketOfFruits.add(new Fruit(369, "blueberries"));
basketOfFruits.add(new Fruit(248, "apple"));
basketOfFruits.add(new Fruit(968, "peaches"));
basketOfFruits.add(new Fruit(436, "grapes"));
basketOfFruits.add(new Fruit(596, "figs"));
//sorting by the property fruitName
Collections.sort(basketOfFruits, (f1, f2)->{return f1.getFruitName().compareTo(f2.getFruitName());});
You can now print the list (i.e basketOfFruits) and the fruits in the list would be sorted in ASCENDING order (lexicographically).
The output would look like this:
[Fruits [price=248, fruitName=apple], Fruits [price=369, fruitName=blueberries], Fruits [price=596, fruitName=figs], Fruits [price=436, fruitName=grapes], Fruits [price=45, fruitName=nectarine], Fruits [price=123, fruitName=oranges], Fruits [price=968, fruitName=peaches]]
Instead of Collections.sort(), Java streams can also be used (Java 8 and above). The following is the code using Java streams
List<Fruit> sortedFruits = basketOfFruits.stream().sorted( (f1, f2)->{return f1.getFruitName().compareTo(f2.getFruitName());}).collect(Collectors.toList());
here the list is sorted in the same manner as Collections.sort(), but the sorted items would be stored/collected in another list "sortedFruits". So, if we want to print the sorted items of the list, we need to print "sortedFruits" instead of "basketOfFruits" in this case
I have a list of structs that I would like to sort according to a specific element of the struct:
private class myStruct {
public Boolean GUI;
public float CallTime;
public String ReqID;
public String ReqGUID;
public String Stereotype;
public String StereotypeGUID;
}
private List<myStruct> DataList = new ArrayList<myStruct>();
How could I sort DataList by the element "ReqID" without hardcoding it?
Is there a possibility to use Arrays.sort()?
You should use a Comparator.
class YourComparator implements Comparator<myStruct>{
public int compare(myStruct s1, myStruct s2){
//here comes the comparison logic
}
}
And then use this form of the sort() method:
Arrays.sort(T[] arrayToSort, Comparator<T> yourComparator);
It's not very clear whether you use a collection or an array as the data structure.
In case you use a List, then use Collections.sort().
For custom sorting you can implement the Comparable interface.
With this interface you create a method compareTo() which returns a negative number, 0 or a positive number. Based on the return code Collections.sort() can tell if the element has to be before or after another element.
A nice example how to use it can be found in this answer: java class implements comparable
use the Comparator interface like this
public static void main(String[] args) {
List<myStruct> DataList = new ArrayList<myStruct>();
//ADD Objects to DataList here
Collections.sort(DataList, new Comparator() {
public int compare(Object o1, Object o2) {
myStruct p1 = (myStruct) o1;
myStruct p2 = (myStruct) o2;
int ret = -1;
//business logic here
if (Integer.parseInt(p1.ReqGUID) == Integer.parseInt(p2.ReqGUID)) {
ret = 0;
} else if (Integer.parseInt(p1.ReqGUID) > Integer.parseInt(p2.ReqGUID)) {
ret = 1;
} else if (Integer.parseInt(p1.ReqGUID) < Integer.parseInt(p2.ReqGUID)) {
ret = -1;
}//end business logic
return ret;
}
});
}
Here inside the Collections.sort() method I am implementing the Comparator interface and overriding the compare() method. This will actually sort your list based on the business logic you implemented inside the compare() method;
Your class structure look strange to me.. You have public fields inside a private class..
Ideally your fields should be marked private and you can have getters and setters to access them..
As for your problem, you can take a look at two important interfaces taht are defined for this kind of job: - http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Comparator.html and http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Comparable.html..
You use Comparator when you want to have multiple ways to compare your class instance..
You can just create a class implementing the Comparator interface, and pass the instance of this class to Collections.sort() method to use this Comparator for sorting..
In this case, compare() method is used to do the job of comparison.
Alternatively, you can associate only one way of comparing a class instance by making that class implementing Comparable interface.. In this case you need to override compareTo() method..
Here's a sample code using Comparator: -
public class MyComparator implements Comparator<Box> {
#Override
public int compare(Box box0, Box box1) {
int w0 = box0.getWeight();
int w1 = box1.getWeight();
return (w0 > w1? -1 : (w0 == w1) ? 0 : 1);
}
}
public class Box {
private int weight;
public Box() {
}
public Box(int weight) {
this.weight = weight;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}
And Your Main
public class Main {
public static void main(String args[]) {
List<Box> boxList = new ArrayList<Box>();
Collections.sort(boxList, new MyComparator());
}
}
Hope it helps..
You can define your own Comparator and use Collections.sort(), passing that Comparator in. That way you can define different comparators for searching using different fields.
Alternatively your struct can implement the Comparable interface and Collections.sort() can sort using this. This is called using the natural sort order, since it's implicit to your class.
Here's the Java tutorial on sorting and ordering.
Use java.util.Collections.sort() with a Comparator instance. See the JavaDocs.
Use Arrays.sort(T[] a, Comparator<? super T> c)
or Collections.sort(List a, Comparator c)
Simplest solution
Just implement java.lang.Comparable interface in you class like following:
class MyStruct implements Comparable<MyStruct>{
public Boolean GUI;
public float CallTime;
public String ReqID;
public String ReqGUID;
public String Stereotype;
public String StereotypeGUID;
#Override
public int compareTo(MyStruct other) {
return ReqID.compareTo(other.ReqID);
/* also you can use ReqID.compareToIgnoreCase(other.ReqID); */
}
#Override
public String toString() {
return "(" + ReqID + ")";
}
}
Override also toString() method just for printing.
Also, keep in mind that String's compareTo() method sorts using lexicographical order. In case you want numeric ID's it is better to use int or other numerical type.
Following is complete code to sort using Arrays.sort() as well as Collections.sort() - choose what suits you :)
public class MyStructSort {
private final static String[] STRUCT_IDS = {"C", "D", "A", "Aa", "B", "Z", "Aaa" };
private static List<MyStruct> createList() {
List<MyStruct> structList = new ArrayList<MyStruct>();
for (String id: STRUCT_IDS) {
MyStruct struct = new MyStruct();
struct.ReqID = id;
structList.add(struct);
}
return structList;
}
public static void main(String[] args) {
List<MyStruct> dataList = createList();
/* Sort using Lists (Collections) */
Collections.sort(dataList);
System.out.println("List sort:\t" + dataList);
/* Sort using arrays */
MyStruct[] dataArray = dataList.toArray(new MyStruct[dataList.size()]);
Arrays.sort(dataArray);
// print sorted array
System.out.print("Array sort:\t");
for (MyStruct struct: dataArray) {
System.out.print(struct+" ");
}
}
}
This is just demonstration code, so some null-checks and getters and setters would be needed to make it perfect.
I have tried almost everything and I can't seem to get my lists to order themselves.
Here's some code:
private List<Person> names = new ArrayList<Person>();
private Map<Integer, Person> peopleMap = new TreeMap <Integer, Person>();
for(int i = 0; i<20; i++)
{
Person personOne = new Person();
peopleMap.put(personOne.id,personOne);
names.add(personOne);
}
Collections.sort(names);
run();
}
My Person class:
public class Person implements Comparable {
public String name;
public int id;
public Date birthdate;
static int idRecord = 0;
The values are filled with randoms. My date has a date format.
I also have a toString method inside my person class, but for some reason when I try to print my maps it gives me the hashcode (this is the hashcode right?) Person#a62fc3.
Here is my toString inside the person clasS:
public String toString()
{
char tab = '\t';
return ("ID Number: "+id+tab+" Name: "+tab+name+tab+" Birthdate: "+(birthdate.toString()));
}
I should add that I am not able to call my toString method inside my person class. Because it is printing Person#a62fc3.
public void sortByID()
{
char tab = '\t';
for (int i = 1; i<20; i++)
System.out.println((peopleMap.get(i)).toString());
//System.out.println("ID Number: "+(peopleMap.get(i).id)+tab+" Name: "+tab+peopleMap.get(i).name+tab+" Birthdate: "+peopleMap.get(i).birthdate);
run();
}
The commented code will work but the code calling the toString does not print what it should
Compare to method inside of my Person class:
public int compareTo(Object obj) {
Person o = (Person) obj;
if (this.id == o.id) { return 0; }
if (this.id > o.id) { return 1; }
if (this.id < o.id) { return -1; }
return 0;
I can provide more code if it's needed.
Compare by name method and it's output. Should I make an arrayList to store my values in and then sort it in that?
public void sortByName()
{
// char tab = '\t';
for(int j = 1; j<20; j++)
{
// System.out.println("ID Number: "+(names.get(j).id)+tab+" Name: "+tab+peopleMap.get(j).name+tab+" Birthdate: "+peopleMap.get(i).birthdate);
//Person p = names.get(j);
System.out.println(names.get(j).toString());
}
}
Output:
Person#10b30a7
Person#1a758cb
Person#1b67f74
Person#69b332
Person#173a10f
Person#530daa
Person#a62fc3
Person#89ae9e
Person#1270b73
Person#60aeb0
Person#16caf43
Person#66848c
Person#8813f2
Person#1d58aae
Person#83cc67
Person#e09713
Person#de6f34
Person#156ee8e
Person#47b480
Thanks
Well, I can't pinpoint the exact problem, I have a few suggestions.
Maps aren't sorted.
In general, an Map is not sorted, so you will not be able to sort the keys of the map. If you want to sort the Map use the SortedMap interface.
Use Generics when possible
The Comparable interface is generic. You should probably be implementing Comparable<Person>
Then your compareTo() method should look like this:
public int compareTo(Person p) {
if (this.id > p.id) return 1;
else if (this.id < p.id) return -1;
else return 0;
}
The difference between Comparator<Person> and Comparable<Person>
You need to take a look at the Comparator interface as well as the Comparable interface.
Your Person should implement comparable in that way that you usually want a person to be sorted. Then you should write some implementations of Comparator.
public classPersonNameComparator implements Comparator<Person> {
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
}
The importance of using the #Override annotation
It is important to always use the #Override annotation whenever you are trying to override a method of a super class or implement an interface method. The following are a few links regarding why this is a good idea:
Overriding the java equals() method quirk
When do you use Java's #Override annotation and why?
One issue that I see is that TreeMap sorts by key not by value. Your compareTo will not be used in the sorting of the tree since it is the value in the map. Since the key in the map is the id the the items in the tree should be sorted by the id of the person.
How do you know that the map isn't sorted? Can you show us some output that shows that it is not? Are you by any chance changing the ID of the Person after it gets put into the map?
Oh, and what is names compared to personMap? Also, are the ids really contiguous starting from 1? What does this code spit out:
for (Person person : peopleMap.values()) {
System.out.println(person);
}
did you use the #Override method to make sure that you are actually overriding the toString method? It looks like it is still printing out the default toString() (ie the value of the pointer to the object).
see : comparator API.
"The ordering imposed by a Comparator c on a set of elements S is said to be consistent with equals if and only if (compare((Object)e1, (Object)e2)==0) has the same boolean value as e1.equals((Object)e2) for every e1 and e2 in S."
I don't see an equals method in your Person class. The default implementation of equals compares identity. And if you override equals, you must define hashCode two.
And this question : Consistent Equals() results, but inconsistent TreeMap.containsKey() result
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
public class Person implements Comparable<Person> {
public final String name;
public final int id;
public final Date birthdate;
public Person(int id, String name, Date birthdate) {
this.id = id;
this.name = name;
this.birthdate = birthdate;
}
public static void main(String[] args) {
List<Person> list = new ArrayList<Person>();
for (int i = 10; i > 0; i--) {
list.add(new Person(i, "name" + String.valueOf(i), new Date()));
}
System.out.println(list);
Collections.sort(list);
System.out.println(list);
}
#Override
public boolean equals(Object other) {
if (!(other instanceof Person)) {
return false;
}
return this.id == ((Person)other).id;
}
#Override
public int hashCode() {
return 41 * id;
}
#Override
public String toString() {
return "Person<" + id + ">";
}
#Override
public int compareTo(Person other) {
if (!(other instanceof Person)) {
throw new IllegalArgumentException();
}
return this.id - ((Person)other).id;
}
}
Outputs :
[Person<10>, Person<9>, Person<8>, Person<7>, Person<6>, Person<5>, Person<4>, Person<3>, Person<2>, Person<1>]
[Person<1>, Person<2>, Person<3>, Person<4>, Person<5>, Person<6>, Person<7>, Person<8>, Person<9>, Person<10>]