Каков наилучший способ удаления дубликатов в массиве в Java?

У меня есть массив объектов, для которого дубликаты дублируются/фильтруются. Я собирался просто переопределить equals и hachCode в элементах Object, а затем вставить их в Set... но я решил, что должен по крайней мере опросить stackoverflow, чтобы узнать, есть ли другой способ, возможно, какой-нибудь умный метод какого-либо другого API?

Ответы

Ответ 1

Я бы согласился с вашим подходом переопределить hashCode() и equals() и использовать что-то, что реализует Set.

Это также делает абсолютно понятным для любых других разработчиков, что требуется недвойственная характеристика.

Еще одна причина - теперь вы можете выбрать реализацию, которая наилучшим образом отвечает вашим потребностям:

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

Ответ 2

Я нашел это в Интернете

Вот два метода, которые позволяют удалить дубликаты в ArrayList. removeDuplicate не поддерживает порядок, когда removeDuplicateWithOrder поддерживает порядок с некоторыми издержками производительности.

  • Метод removeDuplicate:

    /** List order not maintained **/
    public static void removeDuplicate(ArrayList arlList)
    {
     HashSet h = new HashSet(arlList);
     arlList.clear();
     arlList.addAll(h);
    }
    
  • Метод removeDuplicateWithOrder:

    /** List order maintained **/
    public static void removeDuplicateWithOrder(ArrayList arlList)
    {
       Set set = new HashSet();
       List newList = new ArrayList();
       for (Iterator iter = arlList.iterator(); iter.hasNext();) {
          Object element = iter.next();
          if (set.add(element))
             newList.add(element);
       }
       arlList.clear();
       arlList.addAll(newList);
    }
    

Ответ 3

Переопределение equals и hashCode и создание набора было моей первой мыслью. Хорошая практика иметь некоторую переопределенную версию этих методов в любом случае в иерархии наследования.

Я думаю, что если вы используете LinkedHashSet, вы даже сохраните порядок уникальных элементов...

Ответ 4

В принципе, вам нужна реализация LinkedHashSet<T>, которая поддерживает интерфейс List<T> для произвольного доступа. Следовательно, это то, что вам нужно:

public class LinkedHashSetList<T> extends LinkedHashSet<T> implements List<T> {

// Implementations for List<T> methods here ...

}

Реализация методов List<T> обеспечила бы доступ и управление базовым LinkedHashSet<T>. Хитрость заключается в том, чтобы этот класс работал правильно, когда вы пытались добавить дубликаты с помощью методов List<T> add (исключение или повторное добавление элемента в другом индексе были бы параметрами: вы можете либо выбрать один из них, либо сделать настраиваемый пользователями этого класса).

Ответ 5

Я хотел бы повторить точку зрения Джейсона в комментариях:

Зачем ставить себя в этот момент?

Зачем использовать массив для структуры данных, который не должен содержать дубликатов вообще?

Используйте Set или SortedSet (когда элементы также имеют естественный порядок), чтобы удерживать элементы. Если вам нужно сохранить порядок вставки, вы можете использовать LinkedHashSet, как было указано.

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

Ответ 6

Конечно, исходное сообщение задает вопрос: "Как вы получили этот массив (который мог содержать дублированные записи)?"

Вам нужен массив (с дубликатами) для других целей или вы можете просто использовать Set с самого начала?

В качестве альтернативы, если вам нужно знать количество вхождений каждого значения, вы можете использовать Map<CustomObject, Integer> для отслеживания счетчиков. Кроме того, может быть полезно определение классов Multimap Google Collections.

Ответ 7

Использовать Список toRemove для записи элемента в первый раз iterator напасть на него, после чего снова встретиться с записанным элементом, удалите его с помощью iterator.remove()


 private void removeDups(List list) {
        List toRemove = new ArrayList();
        for(Iterator  it = list.iterator(); it.hasNext();) {
            Object next = it.next();
            if(!toRemove.contains(next)) {
                toRemove.add(next);
            } else {
                it.remove();
            }
        }
        toremove.clear();
   } 

Ответ 8

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

Ответ 9

Говоря из общего стандарта программирования, вы всегда можете дважды перечислить коллекции, а затем сравнить источник и цель.

И если ваше внутреннее перечисление всегда запускает одну запись после источника, оно довольно эффективно (псевдокод следует следовать)

foreach ( array as source )
{
    // keep track where we are in the array
    place++;
    // loop the array starting at the entry AFTER the current one we are comparing to
    for ( i=place+1; i < max(array); i++ )
    {
        if ( source === array[place] )
        {
            destroy(array[i]);
        }
    }
}

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