2016-12-09 17 views
0

Я пытаюсь устранить повторяющиеся объекты из списка с помощью TreeSet с пользовательским Comparator. Для этого кода:Компаратор не работает для типов объектов в TreeSet

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, р2> 2, p3-> 3, p4-> 4, P1-> 1, p3-> 3]

Ожидаемые результаты на консоли: [P1-> 1, р2> 2, p3-> 3, p4-> 4]

Почему я получаю p1 и p3 снова в наборе? Где я ошибаюсь в Comparator?

Примечание: это всего лишь пример фрагмента кода. В моей «реальной» код, который я не могу переопределить equals или hashcode

+0

Что касается реализации правильного метода равенства для 'Pass', тогда используйте' obj1.ref.equals (obj2.ref) 'вместо' obj1.ref == obj2.ref'. – Mritunjay

+0

Пробовал, что. Без изменений. – Sujju

+1

Почему вы не отправляете код, который компилируется .. – Jobin

ответ

4

Если вы нарушаете договор о 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 класс, который будет содержать соответствующие атрибуты, определяют Key «s hashCode() и equals() и использовать HashMap<Key, Pass>. Альтернативно, Key может быть просто оболочкой, которая содержит ссылку на Pass и выводит ее хэш-код и равна информации от полей Pass.

1

Ваша проблема в том, что вы нарушите договор Comparator, в котором говорится, что если compare(a, b) возвращает положительное целое число, compare(b, a) должно возвращать отрицательное целое число. Помимо других требований, таких как переходные сравнения. В вашей реализации вы либо возвращаете 0, либо 1, что не соответствует этому договору, поэтому TreeSet не может нормально работать.

+0

Как ни странно, OP не нарушает транзитивности, потому что он всегда возвращает 1 для разных элементов, поэтому 'a < b < c => a

+0

Я знаю, я только что упомянул об этом, поэтому он учитывает это при переопределении своего компаратора. :-) – Vampire