使用多个键对Java对象进行排序
我有一个Duck对象的集合,我想使用多个键对它们进行排序。
class Duck {
DuckAge age; //implements Comparable
DuckWeight weight; //implements Comparable
String name;
}
List ducks = Pond.getDucks();
例如。 我想主要按体重分类,其次按年龄分类。 如果两只鸭子的体重和年龄完全相同,那么我们就以它们的名字作为三级键来区分它们。 我可能会做这样的事情:
Collections.sort(ducks, new Comparator(){
@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分支
7个解决方案
51 votes
番石榴更优雅:
return ComparisonChain.start()
.compare(d1.weight, d2.weight)
.compare(d1.age, d2.age)
.compare(d1.name, d2.name)
.result();
Apache commons-lang具有类似的构造CompareToBuilder。
JB Nizet answered 2020-02-03T23:02:57Z
20 votes
List ducks = new ArrayList();
Collections.sort(ducks, new Comparator() {
@Override
public int compare(Duck o1, Duck o2) {
return new org.apache.commons.lang.builder.CompareToBuilder().
append(o1.weight, o2.weight).
append(o1.age, o2.age).
append(o1.name, o2.name).
toComparison();
}
});
Boris Pavlović answered 2020-02-03T23:03:12Z
14 votes
首先,您的解决方案并不慢。
如果您真的想要另一种方法,请给每只鸭子一个“分数”,该分数实质上是一个单一数字,是它们三个特征的总和,但是具有很大的权重(几乎是不可避免的双关语),而年龄则较小 ; 还有一个很小的名字。
您可以为每个特性分配约10位,因此对于每个特性,您必须在0..1023范围内。
score = ( (weight << 10) + age) << 10 + name;
这可能是完全不需要的,但是无论如何:)
Noxville answered 2020-02-03T23:03:46Z
13 votes
Java 8解决方案:
Comparator cmp = Comparator.comparing(Duck::getWeight)
.thenComparing(Duck::getAge)
.thenComparing(Duck::getName);
糟糕的lambda,方法参考和默认方法:)! 太糟糕了,我们必须定义getter或使用显式的lambda,如下所示:
Comparator cmp = Comparator
.comparing((Duck duck)-> duck.weight)
.thenComparing((Duck duck)-> duck.age)
.thenComparing(duck-> duck.name);
类型推断不适用于隐式Lambda,因此您必须指定前两个Lambda的参数类型。 Brian Goetz在此答案中的更多细节。
andras answered 2020-02-03T23:04:15Z
6 votes
您可以使用Apache Commons Lang中的CompareToBuilder。 (它解释了可比性,但也适用于Comparator)。
Thirler answered 2020-02-03T23:04:35Z
4 votes
您可以使用Commons BeanUtils的链接BeanComparators:
Comparator comparator = new BeanComparator("weight", new BeanComparator("age"));
[http://commons.apache.org/beanutils/v1.8.3/apidocs/org/apache/commons/beanutils/BeanComparator.html]
Emmanuel Bourg answered 2020-02-03T23:04:59Z
4 votes
我刚刚重写了没有嵌套else语句的代码。 你现在喜欢吗?
@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.age);
}
AlexR answered 2020-02-03T23:05:19Z