使用多个键排列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); }