如何通过某些属性对对象列表进行排序


145

我上课简单

public class ActiveAlarm {
    public long timeStarted;
    public long timeEnded;
    private String name = "";
    private String description = "";
    private String event;
    private boolean live = false;
}

List<ActiveAlarm>骗局。如何按升序排序timeStarted,然后按timeEnded?有人可以帮忙吗?我知道在C ++中具有通用算法和重载运算符<,但是我是Java新手。


@Yishai的回答在本文中演示了如何使用比较器链接将枚举优雅地用于自定义排序和分组排序(多个参数)。
gunalmel 2012年

Answers:


140

使ActiveAlarm实现Comparable<ActiveAlarm>Comparator<ActiveAlarm>在单独的类中实现。然后致电:

Collections.sort(list);

要么

Collections.sort(list, comparator);

通常,Comparable<T>如果有一个单一的“自然”排序顺序,则实施是一个好主意...否则(如果您碰巧想要按特定顺序进行排序,但可能同样容易地希望使用另一个顺序),则最好实现Comparator<T>。老实说,这种特殊情况可能会发生任何一种……但是我可能会坚持使用更灵活的Comparator<T>选择。

编辑:示例实现:

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;
  }
}

1
该compare()函数可能不在Long中,因为实现起来更加琐碎:return a-b;
papercrane 2014年

5
@papercrane:不,由于溢出原因而失败。考虑一下a = Long.MIN_VALUE, b = 1
乔恩·斯基特

3
从API 19(KitKat)开始,Long现在拥有.compare
Martin Marconcini

123

使用 Comparator

例如:

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));
        }
    });

从Java 8开始,您可以简单地使用lambda表达式来表示Comparator实例。

Collections.sort(scores, (s1, s2) -> { /* compute and return int */ });

1
怎么compareTo()办?它从何而来?我必须在哪里定义它?
Asqiir

1
@Asqiir getScores()是吸气剂用于scores这是一个List<Integer>。当您getScores().get(0)得到一个Integer对象。Integer已经compareTo(anotherInteger)实现了方法,则无需定义它。
walen

什么是get(0)?
阿里·卡其

1
谢谢工作就像一种魅力(我没有.get(0)部分使用它)。我该如何撤销订单?

53

JAVA 8及以上答案(使用Lambda表达式)

在Java 8中,引入了Lambda表达式以使其变得更加容易!与其创建一个具有全部脚手架的Comparator()对象,不如将其简化如下:(以您的对象为例)

Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.timeStarted-a2.timeStarted);

甚至更短:

Collections.sort(list, Comparator.comparingInt(ActiveAlarm ::getterMethod));

一条语句等效于以下内容:

Collections.sort(list, new Comparator<ActiveAlarm>() {
    @Override
    public int compare(ActiveAlarm a1, ActiveAlarm a2) {
        return a1.timeStarted - a2.timeStarted;
    }
});

将Lambda表达式视为仅要求您放入代码的相关部分:方法签名和返回的内容。

您问题的另一部分是如何与多个字段进行比较。为此,您可以使用Lambda表达式将该.thenComparing()函数有效地将两个比较合并为一个:

Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.timeStarted-a2.timeStarted             
       .thenComparing ((ActiveAlarm a1, ActiveAlarm a2) -> a1.timeEnded-a2.timeEnded)
);

上面的代码将首先按排序列表timeStarted,然后按排序timeEnded(对于具有相同记录的记录timeStarted)。

最后一点:比较“ long”或“ int”原语很容易,您可以从另一个中减去一个。如果要比较对象(“长”或“字符串”),建议您使用它们的内置比较。例:

Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.name.compareTo(a2.name) );

编辑:感谢卢卡斯·埃德为我指出的.thenComparing()职能。


4
您可能会喜欢新的Java 8 API Comparator.comparing().thenComparing()...
Lukas Eder,2016年

1
当心与返回的差异。万一发生溢出,您可能会得到错误的结果。
krzychu

2
恕我直言,这是恕我直言的简单排序方法,再次假设您没有明显的自然顺序。您也不需要再打Collections了,您可以直接打到清单上。例如:myList.sort(Comparator.comparing(Address::getZipCode).thenComparing(Compartor.comparing(Address::getStreetName));
CeePlusPlus,

20

我们可以通过以下两种方式之一对列表进行排序:

1.使用Comparator:需要在多个位置使用排序逻辑时如果要在单个位置使用排序逻辑,则可以编写一个匿名内部类,如下所示,或者提取比较器并在多个位置使用它

  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;
        }
    });

如果可以使用'Long'而不是'long',则可以对属性进行null检查。

2.使用Comparable(自然排序):如果排序算法始终坚持一个属性:编写一个实现“ Comparable”并重写“ compareTo”方法的类,如下所示

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;
}

}

调用sort方法以基于自然顺序进行排序

Collections.sort(list);

7

在java8 +中,可以这样写成一行:

collectionObjec.sort(comparator_lamda) 要么 comparator.comparing(CollectionType::getterOfProperty)

码:

ListOfActiveAlarmObj.sort((a,b->a.getTimeStarted().compareTo(b.getTimeStarted())))
 

要么

ListOfActiveAlarmObj.sort(Comparator.comparing(ActiveAlarm::getTimeStarted))

5
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;
        }
 }

那应该给你一个大概的主意。完成后,您可以调用Collections.sort()列表。


4

从Java8开始,使用Comparator和可以更干净地完成此操作Lambda expressions

例如:

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);

2

番石榴的比较链:

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();
            }});


1

在Java中,您需要使用static Collections.sort方法。这是CompanyRole对象列表的示例,该列表首先按begin排序,然后按end排序。您可以轻松地适应自己的对象。

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;
            }
        }
    });
}

0

您可以调用Collections.sort()并传递一个Comparator,您需要编写该Comparator来比较对象的不同属性。


0

如前所述,您可以排序:

  • 使对象实现 Comparable
  • 或传递ComparatorCollections.sort

如果两者都做,Comparable则将被忽略并Comparator使用。这有助于价值对象具有自己的逻辑 Comparable,这对于您的价值对象而言是最合理的排序,而每个用例都有其自己的实现。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.