Как найти дубликаты в списке?

Помогите пожалуйста с алгоритмом поиска и вывода дубликатов в списке на Java.

ArrayList<String> allUsers = new ArrayList<>(Arrays.asList("User1", "User2", "User2", "User3", "User4", "User4", "User4", "User5", "User5"));

На выходе должно получится:

{"User2", "User4", "User5"};

Если есть возможность с комментариями, что откуда берется и т.д. И будет хорошо, если получится несколько вариантов решений.


Ответы (3 шт):

Автор решения: Circassian

На котлине можно так

fun getItemsMoreOne(list: List<String>) = list
    .groupBy { it }
    .filter { it.value.size > 1 }
    .map { it.key }
→ Ссылка
Автор решения: default locale

На английском Stack Overflow есть вопрос: Identify duplicates in a List. В ответах к нему приводится множество решений на любой вкус.

Короткий способ, через streams API:

List<String> duplicates = allUsers.stream()
    //группируем в map (пользователь -> количество вхождений)
    .collect(Collectors.groupingBy(Function.identity()))
    //проходим по группам
    .entrySet()
    .stream()
    //отбираем пользователей, встречающихся более одного раза
    .filter(e -> e.getValue().size() > 1)
    //вытаскиваем ключи
    .map(Map.Entry::getKey)
    //собираем в список
    .collect(Collectors.toList());

Способ «вручную» через цикл и два множества:

//множество с дубликатами
final Set<String> duplicates = new HashSet<>();
//множество для отслеживания повторяющихся элементов
final Set<String> tracking = new HashSet<>();
//пробегаемся по всем пользователям
for (String user: allUsers) {
    //добавляем их во множество для отслеживания
    //если не получилось добавить, то значит пользователь уже встречался в списке
    if (!tracking.add(user)) {
        //в этом случае добавляем его во множество дубликатов
        duplicates.add(user);
    }
}

Вместо множества дубликатов тут можно использовать список.

→ Ссылка
Автор решения: Андрей Городецкий

Можно ещё и так:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class Duplicate {
    public static void main(String[] args) {
        List<String> allUsers = new ArrayList<>(Arrays.asList("User1", "User2", "User2", "User3", "User4", "User4", "User4", "User5", "User5", "User4"));
        Set<String> stringSet = new HashSet<>();

        Set<String> setOfDupl = allUsers.stream().filter(e -> !stringSet.add(e)).collect(Collectors.toSet());
        setOfDupl.stream().forEach(System.out::println);
    }
}

Неоптимально, но очень понятно, если с лямбдами знакомы конечно

→ Ссылка