Поиск дубликатов в Stream
[Поиск дубликатов в Stream]
В данной статье мы расскажем вам, как находить дублирующиеся элементы в стримах. Допустим, у вас есть некий стрим с элеменетами, которые могут повторяться, и у вам нужно найти такие элементы. Эту задачу можно решить несколькими способами.
Варианты решения задачи
Есть несколько вариантов найти дубликаты в стриме:
- С помощью дополнительного объекта Set
- С помощью метода Collectors.groupingBy
- С помощью утилитного метода Collections.frequency
Поиск дубликатов с помощью Set
Сначала инициализируем вспомогательный Set, с помощью которого мы будем проверять, является ли следующий элемент стрима дубликатом:
Set<T> elements = new HashSet<>();
Затем в стриме будем добавлять каждый элемент из коллекции в Set с помощью метода add(). Этот метод возвращает true в том случае, если этот элемент ранее не был добавлен в Set:
collection.stream()
.filter(e -> !elements.add(e))
.collect(Collectors.toSet());
Таким образом, мы отфильтруем те элементы, которые встречаются в коллекции более одного раза.
Таким образом, полный код нашего метода может выглядеть следующим образом:
public static <T> Set<T> findDuplicates(Collection<T> collection) {
Set<T> elements = new HashSet<>();
return collection.stream()
.filter(e -> !elements.add(e))
.collect(Collectors.toSet());
}
Проверим его с помощью тестовых данных:
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Alice", "Carl", "Don", "Eugene", "Carl");
System.out.println("Все элементы: " + names);
Set<String> duplicates = findDuplicates(names);
System.out.println("Дубликаты: " + duplicates);
}
В результате мы выведем на экран дублирующиеся элементы:
Поиск дубликатов с помощью Set наиболее быстрый вариант из предложенных в данной статье.
Поиск дубликатов с помощью Collectors.groupingBy
Вместо использования Set, можно решить задачу поиска дубликатов с помощью коллекторов groupingBy и counting:
public static <T> Set<T> findDuplicates(Collection<T> collection) {
return collection.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.stream()
.filter(e -> e.getValue() > 1)
.map(Map.Entry::getKey)
.collect(Collectors.toSet());
}
Коллектор groupingBy вернёт HashMap, который мы снова преобразуем в стрим и фильтруем по количеству вхождений.
Поиск дубликатов с помощью Collections.frequency
Ещё один способ поиска дубликатов в стриме — использование вспомогательного метода Collections.frequency для каждого элемента:
public static <T> Set<T> findDuplicates(Collection<T> collection) {
return collection.stream()
.filter(e -> Collections.frequency(collection, e) > 1)
.collect(Collectors.toSet());
}
Данный метод является самым медленным по скорости работы, так как приходится обходить всю коллекцию объектов для каждого элемента.
Исходный код
import java.util.*;
import java.util.stream.Collectors;
public class FindDuplicatesInStream1 {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Alice", "Carl", "Don", "Eugene", "Carl");
System.out.println("Все элементы: " + names);
Set<String> duplicates = findDuplicates(names);
System.out.println("Дубликаты: " + duplicates);
}
public static <T> Set<T> findDuplicates(Collection<T> collection) {
Set<T> elements = new HashSet<>();
return collection.stream()
.filter(e -> !elements.add(e))
.collect(Collectors.toSet());
}
}
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
public class FindDuplicatesInStream2 {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Alice", "Carl", "Don", "Eugene", "Carl");
System.out.println("Все элементы: " + names);
Set<String> duplicates = findDuplicates(names);
System.out.println("Дубликаты: " + duplicates);
}
public static <T> Set<T> findDuplicates(Collection<T> collection) {
return collection.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.stream()
.filter(e -> e.getValue() > 1)
.map(Map.Entry::getKey)
.collect(Collectors.toSet());
}
}
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
public class FindDuplicatesInStream3 {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Alice", "Carl", "Don", "Eugene", "Carl");
System.out.println("Все элементы: " + names);
Set<String> duplicates = findDuplicates(names);
System.out.println("Дубликаты: " + duplicates);
}
public static <T> Set<T> findDuplicates(Collection<T> collection) {
return collection.stream()
.filter(e -> Collections.frequency(collection, e) > 1)
.collect(Collectors.toSet());
}
}
Заключение
В статье мы разобрали несколько вариантов поиска дубликатов в Java Streams. Самый быстрый их них по производительности — первый, с использованием Set. Но если вам не важна скорость работы, вы можете выбрать любой подходящий вам способ для решения задачи.
Поиск дубликатов в Stream
Комментарии 0