Sorting a list in Java using 2 criteria
I have a li开发者_如何学Gost of objects. Each object contains a String
and a Date
(amongst others).
I want to first sort by the String
and then by the Date
.
How could this be done in the cleanest way possible?
Thanks!
Krt_Malta
With Java 8, this is really easy. Given
class MyClass {
String getString() { ... }
Date getDate() { ... }
}
You can easily sort a list as follows:
List<MyClass> list = ...
list.sort(Comparator.comparing(MyClass::getString).thenComparing(MyClass::getDate));
Given an object class that looks like this:
public class MyObject {
public String getString() { ... }
public Date getDate() { ... }
...
}
Write a custom comparator class like so:
public class ObjectComparator implements Comparator{
public int compare(Object obj1, Object obj2) {
MyObject myObj1 = (MyObject)obj1;
MyObject myObj2 = (MyObject)obj2;
stringResult = myObj1.getString().compareTo(myObj2.getString());
if (stringResult == 0) {
// Strings are equal, sort by date
return myObj1.getDate().compareTo(myObj2.getDate());
}
else {
return stringResult;
}
}
}
Then sort as follows:
Collections.sort(objectList, new ObjectComparator());
Implement a custom Comparator
, using a compare(a,b)
method like the following:
Plain Java:
public int compare(YourObject o1, YourObject o2) {
int result = o1.getProperty1().compareTo(o2.getProperty1()));
if(result==0) result = o1.getProperty2().compareTo(o2.getProperty2());
return result;
}
With Guava (using ComparisonChain
):
public int compare(YourObject o1, YourObject o2) {
return ComparisonChain.start()
.compare(o1.getProperty1(), o2.getProperty1())
.compare(o1.getProperty2(), o2.getProperty2())
.result();
}
With Commons / Lang (using CompareToBuilder
):
public int compare(YourObject o1, YourObject o2) {
return new CompareToBuilder()
.append(o1.getProperty1(), o2.getProperty1())
.append(o1.getProperty2(), o2.getProperty2())
.toComparison();
}
(All three versions are equivalent, but the plain Java version is the most verbose and hence most error-prone one. All three solutions assume that both o1.getProperty1()
and o1.getProperty2()
implement Comparable
).
(Taken from this previous answer of mine)
now do Collections.sort(yourList, yourComparator)
The Comparators answer is correct but incomplete.
StringAndDateComparator implements Comparator<MyObject> {
public int compare(MyObject first, MyObject second) {
int result = first.getString().compareTo(second.getString());
if (result != 0) {
return result;
}
else {
return first.getDate().compareTo(second.getDate());
}
}
GlazedLists has a nice utility method to chain together different comparators to save you from writing this boilerplate. See the chainComparators method for more information.
A simple array can be sorted using 2 lambda experessions as:
Arrays.sort(arr, (i, j) -> (i[0] == j[0] ? j[1] - i[1] : i[0] - j[0]));
means two subarrays i & j within a 2D array arr will be sorted in ascending order based on 0th index of arrays. And if 0th index is equal, then based on 1st index.
Try this method:
Collections.sort(list, comparator)
You should of course have a custom Comparator implementation for your object, as stated by Manoj.
Using java 8 and parallel sorting technique, we can also achieve this as follows:
List<Employee> empss = getEmployees();
Comparator<Employee> combinedComparator = Comparator.comparing(Employee::getFName)
.thenComparing(Employee::getLName);
Employee[] emppArr = employees.toArray(new Employee[empss.size()]);
//Parallel sorting
Arrays.parallelSort(emppArr, combinedComparator);
package core.java.collection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class GroupByComparator {
public static void main(String[] args) {
List <StudentTest> studList = new ArrayList<StudentTest>();
StudentTest s1 = new StudentTest(12 ,"Devendra" ,410);
StudentTest s2 = new StudentTest(11 ,"Devendra" ,430);
StudentTest s3 = new StudentTest(13 ,"Devendra" ,402);
StudentTest s4 = new StudentTest(10 ,"Devendra" ,432);
//Assuming that id may be same
StudentTest s5 = new StudentTest(14 ,"Singraul" ,432);
StudentTest s6 = new StudentTest(14 ,"Abhishek" ,432);
StudentTest s7 = new StudentTest(14 ,"Roshan" ,432);
StudentTest s8 = new StudentTest(14 ,"Bikas" ,432);
StudentTest s9 = new StudentTest(15 ,"Devlal" ,450);
StudentTest s10 = new StudentTest(15 ,"Devlal" ,359);
StudentTest s11= new StudentTest(15 ,"Devlal" ,430);
StudentTest s12 = new StudentTest(15 ,"Devlal" ,420);
studList.add(s1); studList.add(s2); studList.add(s3); studList.add(s4); studList.add(s5);
studList.add(s6); studList.add(s7); studList.add(s8); studList.add(s9); studList.add(s10);
studList.add(s11); studList.add(s12);
Collections.sort(studList, new StudentComparator());
// group by sorting
System.out.println(studList);
}
}
// Group by Comparator for ascending order
class StudentComparator implements Comparator<StudentTest>{
@Override
public int compare(StudentTest newObj, StudentTest oldObj) {
int result =0;
// sort by name first
result= newObj.getStudName().compareTo(oldObj.getStudName());
// sort by student id second
if(result == 0) {
result= newObj.getStudId()-oldObj.getStudId() ; // negative means before
}
// sort by marks third
if(result == 0) {
result= Float.compare(newObj.getMarks(), oldObj.getMarks()); ; // negative means before
}
return result;
}
}
class StudentTest{
private int studId ;
private String studName ;
private float marks ;
public StudentTest(int studId, String studName, float marks) {
super();
this.studId = studId;
this.studName = studName;
this.marks = marks;
}
public int getStudId() {
return studId;
}
public void setStudId(int studId) {
this.studId = studId;
}
public String getStudName() {
return studName;
}
public void setStudName(String studName) {
this.studName = studName;
}
public float getMarks() {
return marks;
}
public void setMarks(float marks) {
this.marks = marks;
}
@Override
public String toString() {
return "StudentTest [studId=" + studId + ", studName=" + studName + ", marks=" + marks + "]";
}
}
Try this way....
studentlist.stream().sorted(Comparator.comparing(Student::getAge).thenComparing(Student::getName)).forEach(System.out::println);
精彩评论