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

问题

我有简单的课程

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

andList<ActiveAlarm>con。如何按升序排序bytimeStarted,然后按timeEnded排序?有人可以帮忙吗?我在C中使用泛型算法和重载运算符<,但我不熟悉Java。


#1 热门回答(120 赞)

要么在单独的类中生成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;
  }
}

#2 热门回答(101 赞)

UsingComparator
例如:

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

#3 热门回答(31 赞)

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

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

最后一点:很容易比较'long'或'int'原语,你只需从另一个中减去一个。如果你要比较对象('Long'或'String'),我建议你使用它们的内置比较。例:

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

编辑:感谢Lukas Eder指点我.thenComparing()功能。