【问题标题】:Comparator doesn't work for object types in a TreeSet比较器不适用于 TreeSet 中的对象类型
【发布时间】:2016-12-09 12:16:04
【问题描述】:

我正在尝试借助 TreeSet 和自定义 Comparator 从列表中消除重复对象。 对于此代码:

class ASDF {
    int i
    Pass ref
    new(Pass p, int i) {
        this.ref = p
        this.i=i
    }
    public static def void main(String[] args) {
        val list = new TreeSet(
            new Comparator<ASDF> {
                override compare(ASDF obj1, ASDF obj2) {
                    if (obj1.ref == obj2.ref && obj1.i == obj2.i) {
                        return 0
                    }
                    return 1
                }
            }
        )
        val a1 = new ASDF(new Pass("p1"), 1)
        val a2 = new ASDF(new Pass("p2"), 2)
        val a3 = new ASDF(new Pass("p3"), 3)
        val a4 = new ASDF(new Pass("p4"), 4)
        list.addAll(
            a1, a2, a3, a4
            ,
            a1, a2, a3, a4
            ,
            a1, a2, a3, a4
            ,
            a1, a2, a3, a4
        )
        println(list.map['''«ref.s»->«i»'''])
    }
}

class Pass {
    @Accessors
    String s
    new (String s) {
        this.s=s
    }
}

控制台实际输出:[p1->1, p2->2, p3->3, p4->4, p1->1, p3->3]

控制台上的预期输出:[p1->1, p2->2, p3->3, p4->4]

为什么我又在集合中得到p1p3Comparator 哪里出错了?

注意:这只是一个示例代码 sn-p。在我的“真实”代码中,我无法覆盖 equalshashcode

【问题讨论】:

  • 如何为Pass 实施适当的equals 方法,然后使用obj1.ref.equals(obj2.ref) 而不是obj1.ref == obj2.ref
  • 试过了。没有变化。
  • 为什么不发布一些可编译的代码..
  • obj1.ref == obj2.ref。试试.equals()

标签: java comparator treeset xtend


【解决方案1】:

如果您违反了Comparator 的合同,请不要指望TreeSet 行为正确。

也就是说,这里你没有使比较器对称

Pass p1 = new Pass("p1");
Pass p2 = new Pass("p2");
compare(p1, p2); // returns 1
compare(p2, p1); // also returns 1 - not good

如果您不关心(甚至无法定义)总排序,那么使用正确定义的hashCode()equals() 以及HashSet 会做得更好。

如果您无法覆盖这些(在您编写时),请创建一个包含相关属性的Key 类,定义KeyhashCode()equals() 并使用HashMap&lt;Key, Pass&gt;。或者,Key 可能只是一个包装器,它包含对 Pass 的引用,并从 Pass' 字段中派生出它的哈希码和等于信息。

【讨论】:

    【解决方案2】:

    您的问题是您违反了Comparator 的合同,该合同规定如果compare(a, b) 返回一个正整数,则compare(b, a) 必须返回一个负整数。除了传递比较等其他要求。在您的实现中,您要么返回不遵循此合同的01,因此TreeSet 当然不能正常工作。

    【讨论】:

    • 奇怪的是,OP 并没有破坏传递性,因为他总是为不同的元素返回 1,所以 a &lt; b &lt; c =&gt; a &lt; c 成立。
    • 我知道,我刚才提到了,所以他在重新实现他的比较器时会考虑到这一点。 :-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 2011-05-04
    • 1970-01-01
    • 1970-01-01
    • 2012-10-05
    相关资源
    最近更新 更多