Удалить дубликаты пользовательских элементов из arraylist [duplicate]

У меня есть ArrayList пользовательских объектов. Я хочу удалить повторяющиеся записи.

Объекты имеют три поля: title, subtitle и id. Если субтитры возникают несколько раз, мне нужен только первый элемент с этим субтитрами (игнорируйте оставшийся объект с этим субтитрами).

21
задан 25 April 2013 в 21:23

13 ответов

List<Item> result = new ArrayList<Item>();
Set<String> titles = new HashSet<String>();

for( Item item : originalList ) {
    if( titles.add( item.getTitle() ) {
        result.add( item );
    }
}

add() из Set возвращает false, если элемент уже существует.

8
ответ дан 15 August 2018 в 15:46

Использовать Collections.sort () для сортировки и использования простого цикла для поиска двойников, например :

Collections.sort(myList);
A previous = null;
for (A elem: myList) {
    if (elem.compareTo(previous) == 0) continue;
    previous = elem;

    [... process unique element ...]
}

Это предполагает, что вы реализуете Comparable в своем типе A.

2
ответ дан 15 August 2018 в 15:46
  • 1
    более эффективный, но менее гибкий; это, вероятно, лучше для больших входных наборов – Riccardo Cossu 28 August 2015 в 17:14

Вы можете использовать решение O (n ^ 2): Используйте list.iterator() для повторной сортировки списка один раз и на каждой итерации повторите его повтор, чтобы проверить, есть ли дубликаты. Если есть - вызов iterator.remove(). Вариант этого заключается в использовании guava's Iterables.filter(list, predicate), где ваша логика фильтрации находится в предикате.

Другой способ (возможно, лучше) - определить методы equals(..) и hashCode(..) для обработки ваших пользовательских логику равенства, а затем просто построить a new HashSet(list). Это очистит дубликаты.

7
ответ дан 15 August 2018 в 15:46

Я бы предложил использовать Set

http://download.oracle.com/javase/6/docs/api/java/util/Set.html

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

Set myset = new HashSet(myArrayList);

. Или просто используйте Set с самого начала и не используйте ArrayList, поскольку он не выполняет требуемую функцию. [ ! d4]

11
ответ дан 15 August 2018 в 15:46
  • 1
    В этом случае НЕ следует полагаться на equals и hashcode, так как пример ищет только одно свойство. Вместо этого создайте новый список с желаемым результатом. – crunchdog 21 April 2011 в 12:48
  • 2
    Если это одно свойство означает, что объект является уникальным, почему он не должен переопределять равные, чтобы он проверял только одно свойство? – Kevin D 21 April 2011 в 12:58
  • 3
    Да, если использование equals велико (fe в некоторых наборах данных Frameworks), и вы хотите объединить свой ArrayList, вы можете сделать это с помощью: myArrayList = new ArrayList(new HashSet(myArrayList)); Но это тяжелая работа, и вы должны сделать это, только если вам придется полагаться на списки в будущем Код (например, Collections.shuffle()) – r00tandy 27 August 2016 в 14:20

Обновление для Java8:

Используя потоки Java8, вы также можете сделать довольно тривиально.

ArrayList<String> deduped;
deduped = yourArrayList.stream()
             .distinct()
             .collect(Collectors.toCollection(ArrayList::new));

Это также имеет преимущество перед тем, как ArrayList → Set → ArrayList поддерживает упорядочение.

2
ответ дан 15 August 2018 в 15:46

Удаляет любые дубликаты в коллекции, сохраняя заказ, если он является упорядоченной коллекцией. Достаточно эффективно для большинства случаев.

public static <I, T extends Collection<I>> T removeDuplicates(T collection)
{
    Set<I> setItems = new LinkedHashSet<I>(collection);
    collection.clear();
    collection.addAll(setItems);

    return collection;
}
4
ответ дан 15 August 2018 в 15:46

В Java 8 вы также можете сделать что-то вроде этого:

yourList.stream().collect(
                          Collectors.toMap(
                                           obj -> obj.getSubtitle(),
                                           Function.identity(), 
                                           (o1,o2) -> o1)
                 .values();

Трюк состоит в том, чтобы собирать поток для сопоставления и предоставлять ключевой коллизионный преобразователь лямбда ((o1,o2) -> o1), который всегда возвращает свой первый параметр , Результатом является коллекция, а не список, но вы можете легко преобразовать ее в список:

new ArrayList(resultCollection);
0
ответ дан 15 August 2018 в 15:46

Решение зависит от обстоятельств.

Если у вас мало данных, переходите к Set Set<T> unique = new HashSet<>(yourList); (используйте LinkedHashSet, если вы заботитесь о заказе. Создает новую коллекцию, но обычно это не проблема.

Если вы хотите изменить существующий список и не хотите / не можете создать новую коллекцию, вы можете удалить дубликаты, как здесь:

List<Integer> numbers =
    new ArrayList<>(asList(1, 1, 2, 1, 2, 3, 5));

System.out.println("Numbers: " + numbers);
ListIterator<Integer> it = numbers.listIterator();
while (it.hasNext()) {
    int i = it.nextIndex();
    Integer current = it.next();
    for (int j = 0; j < i; ++j) {
        if (current.equals(numbers.get(j))) {
            it.remove();
            break;
        }
    }
}
System.out.println("Unique: " + numbers);

Он работает в O (n ^ 2), но он работает. Аналогичная реализация, но проще, когда сортировка списка - работает в O (n) времени. Обе реализации объясняются в Farenda: удаление дубликатов из списка - различные реализации .

0
ответ дан 15 August 2018 в 15:46
List list = (...);

//list may contain duplicates.

//remove duplicates if any
Set setItems = new LinkedHashSet(list);
list.clear();
list.addAll(setItems);

Возможно, вам придется переопределить «equals ()», так что 2 элемента считаются равными, если они имеют один и тот же субтитр (например, тит и субтитры?)

45
ответ дан 15 August 2018 в 15:46
  • 1
    +1. Это решение поддерживает порядок исходного списка – qwerty 26 September 2012 в 09:41
  • 2
    ... но не работает, если у объекта есть член, который используется для сортировки, поскольку хеш отличается, даже если ключ тот же (если другие поля отличаются). – chksr 19 March 2017 в 00:39
[F1]
1
ответ дан 15 August 2018 в 15:46
  • 1
    Ваше решение работает только со списком Integer s. OP специально сказал, что список содержит пользовательские объекты. – Laf 7 August 2013 в 00:46
  • 2
    ну ... замените целое число для этих объектов и измените условие в'inArray' ... – urSus 7 August 2013 в 07:02
 List<YourObject> all = ********//this is the object that you have already  and filled it.
 List<YourObject> noRepeat= new ArrayList<YourObject>();

    for (YourObject al: all) 
    {
        boolean isPresent = false;
        // check if the current objects subtitle already exists in noRepeat
        for (YourObject nr : noRepeat) 
       {
            if (nr.getName().equals(al.getName())
              {
                isFound = true;//yes we have already
                 break;
              }
        }

        if (!isPresent) noRepeat.add(al);//we are adding if we don't have already
    }
возьмите один новый объект ArrayList одного и того же типа один за другим, добавьте все старые элементы arraylists в этот новый объект arraylist, но перед добавлением каждой проверки объекта в новый arraylist, если есть какой-либо объект с тем же subtitle.if новый arraylist содержит такие субтитры, не добавляйте его. иначе добавьте его
0
ответ дан 15 August 2018 в 15:46

Если я правильно понял, у вас есть ArrayList<Custom>, назовем его list. У вашего класса Custom есть поле субтитров, скажем, с помощью метода getSubtitle(), который возвращает String. Вы хотите сохранить только первый уникальный субтитр и удалить оставшиеся дубликаты. Вот как вы можете это сделать:

Set<String> subtitles = new HashSet<String>();
for (Iterator<Custom> it = list.iterator(); it.hasNext(); ) {
    if (!subtitles.add(it.next().getSubtitle())) {
        it.remove();
    }
}
6
ответ дан 15 August 2018 в 15:46

Другой метод Использование потоков Java8 также можно сделать довольно круто

Список списков клиентов

Список unique = CustomerLists.stream (). collect (collectAndThen (toCollection (() - > new TreeSet & lt;> (compareLong (Customer :: getId))), ArrayList :: new));

0
ответ дан 15 August 2018 в 15:46

Другие вопросы по тегам:

Похожие вопросы: