使用多个键排列Java对象

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

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

例如。 我想根据他们的体重来sorting, 其次是他们的年龄 。 如果两只鸭子拥有完全相同的体重和完全相同的年龄,那么让我们用他们的名字作为第三把钥匙来区分它们。 我可能会这样做:

 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); } }); 

那么我经常这样做,但是这个解决scheme没有正确的气味。 它不能很好地扩展,很容易搞砸。 当然,必须有一个更好的方式来分类使用多个键鸭! 有谁知道更好的解决scheme吗?

编辑删除不必要的else分支

番石榴更优雅:

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

Apache commons-lang有一个类似的构造, CompareToBuilder

 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(); } }); 

首先,你的解决scheme不是那么慢。

如果你真的想要另一种方法,那么给每只鸭子一个“分数”,其实质上是一个单一的数字,这是他们的三个特征的总和,但是对于体重而言有一个巨大的权重(原谅几乎不可避免的双关语) ; 和一个非常小的名字。

您可以为每个特征分配〜10位,因此对于每个特征,您必须在0..1023范围内。

 score = ( (weight << 10) + age) << 10 + name; 

这可能是完全不需要的,但无论如何:)

Java 8解决scheme:

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

Hooray为lambdas,方法引用和默认方法:)! 太糟糕了,我们必须定义getter,或者使用明确的lambdaexpression式 ,如下所示:

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

types推断不适用于隐式lambdas,所以你必须指定前两个lambdaexpression式的参数types。 Brian Goetz的回答更多细节。

你可以使用Apache Commons Lang的CompareToBuilder。 (这个解释可比,但也适用于比较器)。

你可以使用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

我刚刚重写你的代码没有嵌套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); }