2013-07-31 19 views
1

У меня есть список объектов. Объект выглядит примерно так:Как фильтровать список с помощью пользовательского равенства

class Data { 

    ... 

    private X somethig; 
    private Y somethigElse; 

    public boolean customEquals(Object obj) { 
     if (this == obj) { 
      return true; 
     } 
     if (obj == null) { 
      return false; 
     } 
     if (!(obj instanceof Data)) { 
      return false; 
     } 
     Data other = (Data) obj; 
     if (something == null) { 
      if (other.something != null) { 
       return false; 
      } 
     } else if (!something.equals(other.something)) { 
      return false; 
      } 
     if (somethigElse == null) { 
      if (other.somethigElse != null) { 
      return false; 
      } 
     } else if (!somethigElse.equals(other.somethigElse)) { 
      return false; 
     } 
     return true;  
    } 

    public boolean equals(Object obj) { 
     ... 
    } 

    public int hashCode() { 
     ... 
    } 

    getters/setters 

} 

Мне нужно отфильтровать список, чтобы получить от него отдельные объекты.

Обратите внимание, что методы equals и hashCode реализованы (они используют другие поля), и я не могу использовать equals для этой задачи. Таким образом, равенство не определяется равными, а свойствами «что-то» и «somethigElse». Как я могу это сделать?

Я попытался:

final Comparator<Data> comparator = new Comparator<Data>() { 

    @Override 
    public int compare(Data o1, Data o2) { 
      return o1.customEquals(o2) ? 0 : 1; 
    } 
}; 
Set<Data> set = new TreeSet<Data>(comparator); 
set.addAll(list); 
System.out.println(set); 

Но множество еще содержит некоторые объекты в несколько раз.

+1

Тот факт, вы сделали * somethig * и * somethigelse * частные переменные члены делает меня съежиться - но я получаю точку: D – jdero

+3

Ваш сравнить метод сломанный , Для двух объектов, которые не равны, оба сравнения (a, b) и compare (b, a) возвращают положительное значение. Это делает поведение вашего TreeSet неопределенным. – Buhb

+1

Можете ли вы переубедить equals(), чтобы использовать что-то и что-то еще? Кроме того, если вы хотите только отдельные объекты, почему бы не использовать Set? – NickJ

ответ

3

Это потому, что вы не обеспечиваете надлежащую функцию заказа.

TreeSet алгоритм сортировки делает несколько предположений, как:

compare(a, b) > 0 => compare(b, a) < 0 
compare(a, b) > 0 && compare(b, c) > 0 => compare(a, c) > 0 

и так далее.

Внедрение правильного сравнения, а не только «равно», и оно должно работать.

final Comparator<Data> comparator = new Comparator<Data>() { 

    @Override 
    public int compare(Data o1, Data o2) { 
     int k = o1.getSomething().compareTo(o2.getSomething(); 
     if (k != 0) { 
      return k; 
     } 
     return o1.getSomethingElse() - o2.getSomethingElse(); 
    } 
}; 

Это потому, что TreeSet является SortedSet, и вы говорите, что каждый новый элемент, который прибывает больше, чем другие, но сам по себе.

Давайте сделаем упрощение, чтобы иметь более короткий пример того, что происходит, предположим, что мы используем только цифры с вашим компаратором, а хранилище представляет собой массив (и двоичный поиск), а не дерево, потому что его легче представлять.

Мы получили номер 1, это единственный элемент, поэтому массив [1].

Теперь мы получаем 0, но, как вы говорите, что он больше, мы получаем [1, 0].

Теперь добавим 3, мы получим [1, 0, 3].

Добавить еще 1, бисекции будет пытаться сравнить его со средним элементом 0 и видеть, что это больше, перейти на другую половину, сравнить с 3 и это снова больше, так что мы получаем [1, 0, 3, 1].

Если мы добавим еще один 1, теперь он увидит, что элемент уже существует и не будет его добавлять, но если вы добавите любое другое число, и бывает, что его повторения не находятся ни в одной из точек биссекции, это всегда будет заканчиваться в конце массива.

+0

См. Отредактированный ответ. Проблема в том, что я не забочусь о сравнении свойств. Я просто забочусь о равенстве. – Behnil

+0

ОК, вы этого не делаете, но 'TreeSet' делает – fortran

1

Возможно, вам нужно исправить ваш compare():

public int compare(Data o1, Data o2) 
{ 
    int i = o1.getSomething().compareTo(o2.getSomething()); 
    if (i != 0) return i; 
    return o1.getSomethingElse()- o2.getSomethingElse(); 
} 
Смежные вопросы