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

Jen*_*fer 134 java sorting

我有简单的课程

public class ActiveAlarm {
    public long timeStarted;
    public long timeEnded;
    private String name = "";
    private String description = "";
    private String event;
    private boolean live = false;
}
Run Code Online (Sandbox Code Playgroud)

List<ActiveAlarm>con.如何按升序排序timeStarted,然后按timeEnded?有人可以帮忙吗?我知道在C++中使用泛型算法和重载运算符<,但我是Java的新手.

Jon*_*eet 137

在单独的类中制作ActiveAlarm工具Comparable<ActiveAlarm>或实现Comparator<ActiveAlarm>.然后打电话:

Collections.sort(list);
Run Code Online (Sandbox Code Playgroud)

要么

Collections.sort(list, comparator);
Run Code Online (Sandbox Code Playgroud)

一般来说,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;
  }
}
Run Code Online (Sandbox Code Playgroud)

  • @papercrane:不,因溢出原因而失败.考虑`a = Long.MIN_VALUE,b = 1`. (5认同)
  • 截至API 19(KitKat)Long现在有一个`.compare` (3认同)

Jig*_*shi 114

运用 Comparator

例如:

class Score {

    private String name;
    private List<Integer> scores;
    // +accessor methods
}
Run Code Online (Sandbox Code Playgroud)
    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));
        }
    });
Run Code Online (Sandbox Code Playgroud)

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

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

  • @Asqiir `getScores()` 是 `scores` 的 getter,它是一个 `List&lt;Integer&gt;`。当你执行“getScores().get(0)”时,你会得到一个“Integer”对象。`Integer` 已经实现了 `compareTo(anotherInteger)` 方法,您不必定义它。 (2认同)

Joh*_*ler 43

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

在Java 8中,引入了Lambda表达式以使其更容易!您可以按如下方式简化它,而不是使用所有脚手架创建Comparator()对象:(以您的对象为例)

Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.timeStarted-a2.timeStarted);
Run Code Online (Sandbox Code Playgroud)

甚至更短:

Collections.sort(list, Comparator.comparingInt(ActiveAlarm ::getterMethod));
Run Code Online (Sandbox Code Playgroud)

该声明等同于以下内容:

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

将Lambda表达式视为只需要输入代码的相关部分:方法签名和返回的内容.

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

Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.timeStarted-a2.timeStarted             
       .thenComparing ((ActiveAlarm a1, ActiveAlarm a2) -> a1.timeEnded-a2.timeEnded)
);
Run Code Online (Sandbox Code Playgroud)

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

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

Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.name.compareTo(a2.name) );
Run Code Online (Sandbox Code Playgroud)

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

  • 您可能会欣赏新的Java 8 API`Comparator.comparing().thenComparing()`... (4认同)
  • 恕我直言,这是更简单的排序方法,再次假设您没有明显的自然顺序。你也不需要再调用`Collections`,你可以直接调用列表。例如:`myList.sort(Comparator.comparing(Address::getZipCode).thenComparing(Compartor.comparing(Address::getStreetName));` (2认同)

Jag*_*esh 19

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

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;
        }
    });
Run Code Online (Sandbox Code Playgroud)

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

2.使用Comparable(自然排序):如果sort算法总是坚持一个属性:编写一个实现'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;
}
Run Code Online (Sandbox Code Playgroud)

}

调用sort方法根据自然顺序排序

Collections.sort(list);
Run Code Online (Sandbox Code Playgroud)


Kar*_*yan 6

在java8 +中,可以如下写成一行,

collectionObjec.sort(comparator_lamda)或比较器.comparing(CollectionType :: getterOfProperty)

代码:

ListOfActiveAlarmObj.sort((a,b->a.getTimeStarted().compareTo(b.getTimeStarted())))
Run Code Online (Sandbox Code Playgroud)

要么

ListOfActiveAlarmObj.sort(Comparator.comparing(ActiveAlarm::getTimeStarted))
Run Code Online (Sandbox Code Playgroud)


Kal*_*Kal 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;
        }
 }
Run Code Online (Sandbox Code Playgroud)

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


Mat*_* G. 5

由于Java8这甚至可以使用清洁剂的组合来实现ComparatorLambda expressions

例如:

class Student{

    private String name;
    private List<Score> scores;

    // +accessor methods
}

class Score {

    private int grade;
    // +accessor methods
}
Run Code Online (Sandbox Code Playgroud)
    Collections.sort(student.getScores(), Comparator.comparing(Score::getGrade);
Run Code Online (Sandbox Code Playgroud)