Подтвердить что ты не робот

Как проверить, существует ли какой-либо дубликат в потоках Java 8?

В java 8, какой лучший способ проверить, содержит ли List какой-либо дубликат?

Моя идея была примерно такой:

list.size() != list.stream().distinct().count()

Это лучший способ?

4b9b3361

Ответ 1

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

public static <T> boolean areAllUnique(List<T> list){
    Set<T> set = new HashSet<>();

    for (T t: list){
        if (!set.add(t))
            return false;
    }

    return true;
}

будет более эффективным, так как он может дать вам false сразу, когда будет найден первый неуникальный элемент.

Этот метод также может быть переписан как (при условии непараллельных потоков и потокобезопасной среды) с использованием Stream#allMatch который также является коротким замыканием (немедленно возвращает false для первого элемента, который не удовлетворяет условию)

public static <T> boolean areAllUnique(List<T> list){
    Set<T> set = new HashSet<>();
    return list.stream().allMatch(t -> set.add(t));
}

или как @Holger упоминается в комментарии

public static <T> boolean areAllUnique(List<T> list){
    return list.stream().allMatch(new HashSet<>()::add);
}

Ответ 2

Я использовал следующее:
1. return list.size() == new HashSet<>(list).size(); ,

Я не уверен, как это сравнивается с:
2. return list.size() == list.stream().distinct().count();
а также
3. return list.stream().sequential().allMatch(new HashSet<>()::add);
с точки зрения производительности.

Последний (# 3) имеет возможность обрабатывать не только коллекции (например, списки), но и потоки (без явного сбора их).

Upd.: Последний (# 3) кажется лучшим не только потому, что он может обрабатывать чистые потоки, но и потому, что он останавливается на первом дубликате (в то время как # 1 и # 2 всегда повторяются до конца) - как @Pshemo сказал в комментарии.

Ответ 3

Вы можете использовать счетный коллектор.

Stream.of(1, 3, 4, 6, 7, 5, 6)
            .collect(Collectors.groupingBy(
                    Function.identity(), Collectors.counting()))
            .entrySet().stream().anyMatch(e -> e.getValue() > 1)

Ответ 4

Начал этот класс как StreamTool, но я думаю, что должен быть еще лучший способ с уменьшением или похожим:

public class StreamTool {

    /**
     * Whether stream records are unique in that stream.
     * @param <T> Type of records
     * @param records
     * @return true if there are no duplicates, false otherwise
     */
    public static <T> boolean isUnique(Stream<T> records) {
        return records.allMatch(new HashSet<>()::add);
    }
}

Ответ 5

Set<T> found = new HashSet<>();
boolean containsDuplicate = list.stream().anyMatch(el -> !found.add(el));