使用多个键对 Java 对象进行排序

2022-08-31 17:47:51

我有一个 Duck 对象的集合,我想使用多个键对它们进行排序

class Duck {
    DuckAge age; //implements Comparable
    DuckWeight weight; //implements Comparable
    String name;
}
List<Duck> ducks = Pond.getDucks();

例如。我想主要按它们的权重对它们进行排序,其次是按它们的年龄排序。如果两只鸭子的体重和年龄完全相同,那么让我们用它们的名字作为三级键来区分它们。我可能会做这样的事情:

Collections.sort(ducks, new Comparator<Duck>(){
    @Override
    public int compare(Duck d1, Duck d2){
        int weightCmp = d1.weight.compareTo(d2.weight);
        if (weightCmp != 0) {
            return weightCmp;
        }
        int ageCmp = d1.age.compareTo(d2.age);
        if (ageCmp != 0) {
            return ageCmp;
        }
        return d1.name.compareTo(d2.name);
    }
});

好吧,我经常这样做,但是这个解决方案闻起来不对。它不能很好地扩展,而且很容易搞砸。当然,必须有更好的方法来使用多个键对鸭子进行分类!有谁知道更好的解决方案吗?

编辑删除了不必要的分支else


答案 1

番石榴更优雅:

return ComparisonChain.start()
     .compare(d1.weight, d2.weight)
     .compare(d1.age, d2.age)
     .compare(d1.name, d2.name)
     .result();

Apache commons-lang也有类似的结构,CompareToBuilder


答案 2

Java 8 解决方案:

Comparator<Duck> cmp = Comparator.comparing(Duck::getWeight)
    .thenComparing(Duck::getAge)
    .thenComparing(Duck::getName);

Hooray for lambdas, method reference, and default methods:)!太糟糕了,我们必须定义getters,或者使用显式的lambda,就像这样:

Comparator<Duck> cmp = Comparator
    .comparing((Duck duck)-> duck.weight)
    .thenComparing((Duck duck)-> duck.age)
    .thenComparing(duck-> duck.name);

类型推断不适用于隐式 lambda,因此您必须指定前两个 lambda 的参数类型。布莱恩·戈茨(Brian Goetz)的回答中有更多细节。


推荐