我收集了一些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);
}
});
我经常这样做,但这个解决方案闻起来并不正确。它不能很好地扩展,并且很容易搞砸。当然必须有一种更好的方法来使用多个键对Ducks进行排序!有人知道更好的解决方案吗?
编辑删除了不必要的else
分支
答案 0 :(得分:49)
Guava更优雅:
return ComparisonChain.start()
.compare(d1.weight, d2.weight)
.compare(d1.age, d2.age)
.compare(d1.name, d2.name)
.result();
Apache commons-lang有一个类似的构造CompareToBuilder
。
答案 1 :(得分:20)
List<Duck> ducks = new ArrayList<Duck>();
Collections.sort(ducks, new Comparator<Duck>() {
@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();
}
});
答案 2 :(得分:14)
首先,您的解决方案不是 慢。
如果你真的想要另一种方法,那就给每只鸭子一个“得分”,这个数字基本上是一个数字,是它们三个特征的总和,但是它具有巨大的权重(借口几乎不可避免的双关语)的重量,一个较小的一个适合年龄;这个名字很小。
您可以为每个特征分配~10位,因此对于每个特征,您必须在0..1023
范围内。
score = ( (weight << 10) + age) << 10 + name;
这可能完全不需要,但无论如何:)
答案 3 :(得分:10)
Java 8解决方案:
Comparator<Duck> cmp = Comparator.comparing(Duck::getWeight)
.thenComparing(Duck::getAge)
.thenComparing(Duck::getName);
Hooray for lambdas,方法引用和默认方法:)!太糟糕了,我们必须定义getter,或使用显式lambdas ,如下所示:
Comparator<Duck> cmp = Comparator
.comparing((Duck duck)-> duck.weight)
.thenComparing((Duck duck)-> duck.age)
.thenComparing(duck-> duck.name);
类型推断不适用于隐式lambda,因此您必须指定前两个lambda的参数类型。 this answer by Brian Goetz中的更多详细信息。
答案 4 :(得分:6)
您可以使用Apache Commons Lang中的CompareToBuilder。 (它解释了可比性,但也适用于比较器)。
答案 5 :(得分:4)
您可以使用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
答案 6 :(得分:4)
我刚刚重写了你的代码而没有嵌套的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);
}