【发布时间】:2021-03-18 14:44:15
【问题描述】:
我有一个对象列表。每个对象都包含一个String 和一个Date(等等)。
我想先按String 排序,然后再按Date。
如何以最干净的方式完成这项工作?
谢谢!
Krt_马耳他
【问题讨论】:
我有一个对象列表。每个对象都包含一个String 和一个Date(等等)。
我想先按String 排序,然后再按Date。
如何以最干净的方式完成这项工作?
谢谢!
Krt_马耳他
【问题讨论】:
使用 Java 8,这真的很容易。给定
class MyClass {
String getString() { ... }
Date getDate() { ... }
}
您可以轻松地对列表进行如下排序:
List<MyClass> list = ...
list.sort(Comparator.comparing(MyClass::getString).thenComparing(MyClass::getDate));
【讨论】:
给定一个如下所示的对象类:
public class MyObject {
public String getString() { ... }
public Date getDate() { ... }
...
}
像这样编写一个自定义比较器类:
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;
}
}
}
然后排序如下:
Collections.sort(objectList, new ObjectComparator());
【讨论】:
使用compare(a,b) 方法实现自定义Comparator,如下所示:
纯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;
}
使用Guava(使用ComparisonChain):
public int compare(YourObject o1, YourObject o2) {
return ComparisonChain.start()
.compare(o1.getProperty1(), o2.getProperty1())
.compare(o1.getProperty2(), o2.getProperty2())
.result();
}
使用Commons / Lang(使用CompareToBuilder):
public int compare(YourObject o1, YourObject o2) {
return new CompareToBuilder()
.append(o1.getProperty1(), o2.getProperty1())
.append(o1.getProperty2(), o2.getProperty2())
.toComparison();
}
(所有三个版本都是等效的,但是纯 Java 版本是最冗长的,因此最容易出错。所有三个解决方案都假定 o1.getProperty1() 和 o1.getProperty2() 都实现了 Comparable。
(取自this previous answer of mine)
【讨论】:
比较者的答案是正确的,但不完整。
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 有一个很好的实用方法,可以将不同的比较器链接在一起,从而避免编写此样板文件。有关详细信息,请参阅chainComparators 方法。
【讨论】:
可以使用 2 个 lambda 表达式对简单数组进行排序:
Arrays.sort(arr, (i, j) -> (i[0] == j[0] ? j[1] - i[1] : i[0] - j[0]));
表示二维数组 arr 中的两个子数组 i 和 j 将根据数组的第 0 个索引按升序排序。如果第 0 个索引相等,则基于第 1 个索引。
【讨论】:
【讨论】:
使用java 8和并行排序技术,我们也可以实现如下:
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 + "]";
}
}
【讨论】:
试试这个方法....
studentlist.stream().sorted(Comparator.comparing(Student::getAge).thenComparing(Student::getName)).forEach(System.out::println);
【讨论】: