使用Lambda表达式对多个属性进行排序

11

这是我的清单:

Name: Ben     || Age: 5 || Group: 1
Name: Andy    || Age: 6 || Group: 2
Name: Charlie || Age: 6 || Group: 2
Name: Ben     || Age: 5 || Group: 1
Name: Andy    || Age: 5 || Group: 2
Name: Charlie || Age: 5 || Group: 1

我想按照Group排序列表,如果Group相等,则按Age排序,如果Age相等,则按Name排序。但是迄今为止,我只能使用Lambda表达式按一个属性进行排序:

list.sort((Object o1, Object o2) -> o1.getGroup().compareTo(o2.getGroup()));

如果我尝试

o1.getGroup().compareTo(o2.getGroup()) && o1.getAge().compareTo(o2.getAge())

出现了错误...

2个回答

19

将 lambda 表达式 改为 lambda {块},您无需指定参数类型:

list.sort((o1, o2) -> {
    int cmp = o1.getGroup().compareTo(o2.getGroup());
    if (cmp == 0)
        cmp = Integer.compare(o1.getAge(), o2.getAge());
    if (cmp == 0)
        cmp = o1.getName().compareTo(o2.getName());
    return cmp;
});

1
你是我的救星 :) 谢谢 - user4754843
5
在这里感谢别人的正确方式是通过给他们的答案点赞。 - Edwin Dalorzo
如何使用原始数组(而不是列表)来完成这个操作?当对“int[] arr”进行排序时,此语法似乎无效:Arrays.sort(arr,<多行lambda>); - PlsWork
@AnnaVopureta 对于按自定义顺序对原始数组进行排序,没有专门的排序方法。Java运行库只有按照自然顺序对原始数组进行排序的方法。请参阅:如何使用自定义比较器对int数组进行排序? - Andreas

16
你可以使用静态方法Comparator.comparing,基于返回可比较值的函数创建一个比较器。这样的比较器可以与其他比较器链接在一起。
假设你的类型被称为Person,那么你会有:
Comparator<Person> c = Comparator
        .comparing(p -> p.getGroup())
        .thenComparing(p -> p.getAge())
        .thenComparing(p -> p.getName())

如果任何一个getter方法返回原始类型,你需要分别使用comparingIntthenComparingInt。您还可以使用方法引用:

Comparator<Person> c = Comparator
        .comparing(Person::getGroup)
        .thenComparing(Person::getAge)
        .thenComparing(Person::getName)

但是,如果你的类根据这些值具有自然顺序,则最好让它实现接口Comparable并在其中编写比较逻辑:

class Person implements Comparable<Person> {
    ...
    @Override
    public int compareTo(Person other) {
        int compare = Integer.compare(getGroup(), other.getGroup());
        if (compare == 0) {
            compare = Integer.compare(getAge(), other.getAge());
        }
        if (compare == 0) {
            compare = getName.compareTo(other.getName());
        }
        return compare;
    }
}

这段代码片段也可以用于lambda表达式:

list.sort((o1, o2) -> {
    int compare = Integer.compare(o1.getGroup(), o2.getGroup());
    if (compare == 0) {
        compare = Integer.compare(o1.getAge(), o2.getAge());
    }
    if (compare == 0) {
        compare = o1.getName.compareTo(o2.getName());
    }
    return compare;
});

1
使用Integer.compare()代替减法,在处理非常大的值时避免出现错误的结果。 - Andreas
1
你的第一个例子不起作用。编译器无法推断出 p 是一个 Person - Holger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接