Удаление дубликатов без переопределения метода хеширования - PullRequest
2 голосов
/ 20 апреля 2010

У меня есть список, который содержит список объектов, и я хочу удалить из этого списка все элементы, которые имеют одинаковые значения в двух своих атрибутах. Я хотел сделать что-то вроде этого:

List<Class1> myList;
....
Set<Class1> mySet = new HashSet<Class1>();
mySet.addAll(myList);

и переопределяющий хеш-метод в Class1, поэтому он возвращает число, которое зависит только от атрибутов, которые я хочу рассмотреть.

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

Какой самый эффективный способ выполнить эту фильтрацию без переопределения метода хеширования?

Спасибо

Ответы [ 5 ]

4 голосов
/ 20 апреля 2010

Переопределение hashCode и equals в Class1 (только для этого) проблематично. В итоге у вашего класса есть неестественное определение равенства, которое может оказаться другим для других текущих и будущих применений класса.

Просмотрите интерфейс Comparator и напишите реализацию Comparator<Class1>, чтобы сравнить экземпляры вашего Class1 на основе ваших критериев; например на основе этих двух атрибутов. Затем создайте экземпляр TreeSet<Class> `для обнаружения дубликатов, используя конструктор TreeSet (Comparator) .

EDIT

Сравнение этого подхода с подходом @Tom Hawtin:

  • Оба подхода используют примерно сравнимое пространство в целом. Внутренние узлы древовидного набора примерно уравновешивают массив хэш-набора и оболочки, которые поддерживают пользовательские методы equals / hash.

  • Подход "обертка + хэш-набор" по времени * (при условии хорошего хеширования) против O(NlogN) для подхода с набором деревьев. Так что это путь, если список ввода, вероятно, будет большим.

  • Подход «древовидная структура» выигрывает в терминах строк кода, которые необходимо написать.

3 голосов
/ 20 апреля 2010

Пусть ваш Class1 реализует Comparable. Затем используйте TreeSet как в вашем примере (то есть используйте метод addAll).

2 голосов
/ 20 апреля 2010

В качестве альтернативы тому, что сказал Роман, вы можете взглянуть на этот SO вопрос о фильтрации с использованием предикатов. Если вы все равно используете Коллекции Google, это может подойти.

1 голос
/ 20 апреля 2010

Я бы предложил ввести класс для понятия частей Class1, который вы хотите считать значимым в этом контексте.Затем используйте HashSet или HashMap.

0 голосов
/ 20 апреля 2010

Иногда программисты усложняют задачу, пытаясь использовать все приятные возможности языка, и ответы на этот вопрос служат примером. Переопределять что-либо в классе - это излишне. Что вам нужно, это:

class MyClass {
  Object attr1;
  Object attr2;
}

List<Class1> list;
Set<Class1> set=....
Set<MyClass> tempset = new HashSet<MyClass>;

for (Class1 c:list) {
  MyClass myc = new MyClass();
  myc.attr1 = c.attr1;
  myc.attr2 = c.attr2;

  if (!tempset.contains(myc)) {
    tempset.add(myc);
    set.add(c);
  }
}

Не стесняйтесь исправлять мелкие иррегуляриты. Возникнут некоторые проблемы в зависимости от того, что вы подразумеваете под равенством для атрибутов (и очевидными изменениями, если атрибуты являются примитивными). Иногда нам нужно писать код, а не просто использовать встроенные библиотеки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...