如何修复Comparator以在TreeSet中使用

时间:2015-01-11 15:02:25

标签: java collections set logic treeset

我有一个带有自定义比较器的TreeSet,但remove()操作不起作用。 这是代码:

new TreeSet<>(new Comparator<Tile>(){
            public int compare(Tile o1, Tile o2){
                if(o1 == o2){
                    return 0;
                }
                if(o1.getValue() > o2.getValue()){
                    return 1;
                }
                return -1;
            }
        });

我认为,使用此比较器,副本定义为o1 == o2,de order基于getValue()升序。但有些事情是错的......什么?

2 个答案:

答案 0 :(得分:3)

  

o1 == o2

这是比较对象引用,而不是值。您没有涵盖值相等的情况。假设调用getValue()并不昂贵,我通常会跳过对象引用等式检查以使我的代码更简单。

public int compare(Tile o1, Tile o2){
    if(o1.getValue() == o2.getValue()){
         return 0;
    }
    if(o1.getValue() > o2.getValue()){
         return 1;
    }
    return -1;
}

或者更简单:

public int compare(Tile o1, Tile o2){
    return o1.getValue() - o2.getValue();
}

答案 1 :(得分:1)

您撰写compare的方式并不符合该方法的合同。您必须满足的条件之一是:

sgn(compare(x, y)) == -sgn(compare(y, x)) for all x and y

但是您的compare方法并不能满足这一条件,因为如果您有两个Tile s xy满足x != y和{{} 1}}然后x.getValue() == y.getValue()compare(x, y)都是compare(y, x)

如果您违反-1的合同,则会收到无法预测的结果,

如果您希望compare的两个实例只有在具有相同标识的情况下才被视为重复项,那么很难看出您如何能够满足上述条件,因此这将使用{{{ 1}}。相反,您可以使用Tile来覆盖TreeSetHashSetequals。如果您无法控制班级hashCode,并且TileTile已被覆盖,那么您可以使用equals或番石榴&hashCode视图#39; s keySet。不幸的是,这些解决方案并没有对收集品进行分类。

如果您需要根据IdentityHashMap返回的值对集合进行排序,并且您只想在实例完全相同时删除重复项,我认为没有任何明智的选择这样做的方式。您可以使用newIdentityHashSet()使用getValue()进行排序(与比较器返回ArrayList一起使用)。每当你需要删除重复项时,你可以做这样的事情

Collections.sort