简体   繁体   English

Java比较器:两个排序条件

[英]Java comparator: Two ordering criteria

I have a simple class that contains a string (name) and an integer (age). 我有一个简单的类,其中包含一个字符串(名称)和一个整数(年龄)。 The objects, that shall be stored in the collection, must not have double name values and shall be sorted according to descending age. 应存储在集合中的对象不得具有双名值,并且应根据年龄的降序进行排序。 The first code example removes all double names, but doesn't contain a second ordering criterion: 第一个代码示例删除所有双精度名称,但不包含第二个排序条件:

public int compare(Person p1, Person p2) {  
    int reVal = 1;

       if(p1.getName().compareTo(p2.getName()) != 0){
       reVal = 1;       
       }
       else {
       reVal = 0;       
       }                               
         return reVal;                  
    } 

The next example comparator shall order the rest set of the objects, that doesn't contain any double names: 下一个示例比较器将对其余对象集进行排序,这些对象集不包含任何重复名称:

public int compare(Person p1, Person p2) {  
    boolean ageGt = (p1.getAge() > p2.getAge());
    int reVal = 1;

       if(p1.getName().compareTo(p2.getName()) != 0){
       if(scoreGt)
            reVal = -1;
       else 
            reVal = 1;      
       }
       else {
       reVal = 0;       
       }                               
         return reVal;                  
    } 

The second comparator orders the objects according their age values correctly, but it allows double names, which I don't understand, because the outer if-statement already checked if the names of both objects are equal. 第二个比较器根据对象的年龄值正确地对其排序,但是它允许使用双名,这是我不明白的,因为外部if语句已经检查了两个对象的名称是否相等。 Why does that happen? 为什么会这样呢?

You have a fundamental problem here: you want at the same time to test for unicity and to order entries. 您这里有一个基本问题:您希望同时测试唯一性订购条目。 There is no builtin collection which will check at the same time that entries are equal and that their comparison is 0. 没有内置集合可以同时检查条目是否相等以及它们的比较是否为0。

For instance, two Set implementations are HashSet and TreeSet : 例如,两个Set实现是HashSetTreeSet

  • HashSet uses Object 's .equals() / .hashCode() to test for equality; HashSet使用Object.equals() / .hashCode()进行相等性测试;
  • TreeSet uses a Comparator (or the objects' Comparable capability if they implement it) to test for equality. TreeSet使用Comparator (或对象的Comparable功能,如果实现的话)来测试是否相等。

This is not quite the same thing. 这不是完全一样的事情。 In fact, with one particular JDK class, that is, BigDecimal , this can get quite surprising: 实际上,对于一个特定的JDK类,即BigDecimal ,这可能会非常令人惊讶:

final BigDecimal one = new BigDecimal("1");
final BigDecimal oneDotZero = new BigDecimal("1.0");

final Set<BigDecimal> hashSet = new HashSet<>();
// BigDecimal implements Comparable of itself, so we can use that
final Set<BigDecimal> treeSet = new TreeSet<>();

hashSet.add(one);
hashSet.add(oneDotZero);
// hashSet's size is 2: one.equals(oneDotZero) == false

treeSet.add(one);
treeSet.add(oneDotZero);
// treeSet's size is... 1! one.compareTo(oneDotZero) == 0

You cannot both have your cake and eat it. 你们不能都吃蛋糕。 Here, you want to test unicity according to the name and comparison according to the age, you must use a Map . 在这里,要根据名称测试唯一性,并根据年龄进行比较,则必须使用Map

As to obtain a sorted list of persons, you will have to do a copy of this map's .values() as a list and use Collections.sort() . 为了获得人员的排序列表,您将必须复制此地图的.values()作为列表,并使用Collections.sort() If you use Guava, this latter part is as simple as Ordering.natural().sortedCopy(theMap.values()) , provided your values implement Comparable . 如果使用番石榴,则后一部分就像Ordering.natural().sortedCopy(theMap.values())一样简单,只要您的值实现Comparable

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM