Я пытаюсь перечислить повторяющиеся элементы в целочисленном списке, например,
List<Integer> numbers = Arrays.asList(new Integer[]{1,2,1,3,4,4});
using Streams of jdk 8. Кто-нибудь пробовал. Чтобы удалить дубликаты, мы можем использовать отдельный () api. Но как насчет поиска повторяющихся элементов? Кто-нибудь может мне помочь?
java
lambda
java-8
java-stream
Шива
источник
источник
Ответы:
Вы можете использовать
Collections.frequency
:numbers.stream().filter(i -> Collections.frequency(numbers, i) >1) .collect(Collectors.toSet()).forEach(System.out::println);
источник
Базовый пример. Первая половина строит частотную карту, вторая половина сокращает ее до отфильтрованного списка. Вероятно, не так эффективно, как ответ Дэйва, но более универсален (например, если вы хотите обнаружить ровно два и т. Д.)
List<Integer> duplicates = IntStream.of( 1, 2, 3, 2, 1, 2, 3, 4, 2, 2, 2 ) .boxed() .collect( Collectors.groupingBy( Function.identity(), Collectors.counting() ) ) .entrySet() .stream() .filter( p -> p.getValue() > 1 ) .map( Map.Entry::getKey ) .collect( Collectors.toList() );
источник
Вам нужен набор (
allItems
ниже) для хранения всего содержимого массива, но это O (n):Integer[] numbers = new Integer[] { 1, 2, 1, 3, 4, 4 }; Set<Integer> allItems = new HashSet<>(); Set<Integer> duplicates = Arrays.stream(numbers) .filter(n -> !allItems.add(n)) //Set.add() returns false if the item was already in the set. .collect(Collectors.toSet()); System.out.println(duplicates); // [1, 4]
источник
filter()
требует предиката без состояния. Ваше «решение» поразительно похоже на пример предиката с отслеживаниемsequential()
, это, вероятно, безопасно. В более общем случае, когда может быть потокparallel()
, он почти гарантированно прерывается странными способами.Способ O (n) будет следующим:
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 4, 4); Set<Integer> duplicatedNumbersRemovedSet = new HashSet<>(); Set<Integer> duplicatedNumbersSet = numbers.stream().filter(n -> !duplicatedNumbersRemovedSet.add(n)).collect(Collectors.toSet());
При таком подходе сложность пространства увеличилась бы вдвое, но это пространство не пустая трата; Фактически, теперь у нас есть только дубликат только как Набор, а также еще один Набор с удалением всех дубликатов.
источник
Моя библиотека StreamEx, которая расширяет потоки Java 8, предоставляет специальную операцию,
distinct(atLeast)
которая может сохранять только элементы, появляющиеся по крайней мере указанное количество раз. Итак, вашу проблему можно решить так:List<Integer> repeatingNumbers = StreamEx.of(numbers).distinct(2).toList();
Внутренне оно похоже на решение @Dave, оно подсчитывает объекты для поддержки других требуемых количеств и поддерживает параллелизм (используется
ConcurrentHashMap
для параллельного потока, ноHashMap
для последовательного). Для больших объемов данных вы можете получить ускорение с помощью.parallel().distinct(2)
.источник
Вы можете получить дубликат следующим образом:
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 4, 4); Set<Integer> duplicated = numbers .stream() .filter(n -> numbers .stream() .filter(x -> x == n) .count() > 1) .collect(Collectors.toSet());
источник
numbers = Arrays.asList(400, 400, 500, 500);
stream
внутреннюю частьstream
стоит дорого.Я думаю, что основные решения вопроса должны быть следующими:
Supplier supplier=HashSet::new; HashSet has=ls.stream().collect(Collectors.toCollection(supplier)); List lst = (List) ls.stream().filter(e->Collections.frequency(ls,e)>1).distinct().collect(Collectors.toList());
ну, не рекомендуется выполнять операцию фильтрации, но для лучшего понимания я ее использовал, более того, в будущих версиях должна быть некоторая настраиваемая фильтрация.
источник
Мультимножество - это структура, поддерживающая количество вхождений каждого элемента. Использование реализации Guava:
Set<Integer> duplicated = ImmutableMultiset.copyOf(numbers).entrySet().stream() .filter(entry -> entry.getCount() > 1) .map(Multiset.Entry::getElement) .collect(Collectors.toSet());
источник
создание дополнительной карты или потока занимает много времени и места…
Set<Integer> duplicates = numbers.stream().collect( Collectors.collectingAndThen( Collectors.groupingBy( Function.identity(), Collectors.counting() ), map -> { map.values().removeIf( cnt -> cnt < 2 ); return( map.keySet() ); } ) ); // [1, 4]
… И по вопросу о том, что является [дубликатом]
public static int[] getDuplicatesStreamsToArray( int[] input ) { return( IntStream.of( input ).boxed().collect( Collectors.collectingAndThen( Collectors.groupingBy( Function.identity(), Collectors.counting() ), map -> { map.values().removeIf( cnt -> cnt < 2 ); return( map.keySet() ); } ) ).stream().mapToInt( i -> i ).toArray() ); }
источник
Если вам нужно только обнаружить наличие дубликатов (вместо того, чтобы перечислять их, чего хотел OP), просто преобразуйте их как в список, так и в набор, а затем сравните размеры:
List<Integer> list = ...; Set<Integer> set = new HashSet<>(list); if (list.size() != set.size()) { // duplicates detected }
Мне нравится этот подход, потому что в нем меньше места для ошибок.
источник
Думаю, у меня есть хорошее решение, как исправить такую проблему - Список => Список с группировкой по Something.a и Something.b. Есть расширенное определение:
public class Test { public static void test() { class A { private int a; private int b; private float c; private float d; public A(int a, int b, float c, float d) { this.a = a; this.b = b; this.c = c; this.d = d; } } List<A> list1 = new ArrayList<A>(); list1.addAll(Arrays.asList(new A(1, 2, 3, 4), new A(2, 3, 4, 5), new A(1, 2, 3, 4), new A(2, 3, 4, 5), new A(1, 2, 3, 4))); Map<Integer, A> map = list1.stream() .collect(HashMap::new, (m, v) -> m.put( Objects.hash(v.a, v.b, v.c, v.d), v), HashMap::putAll); list1.clear(); list1.addAll(map.values()); System.out.println(list1); } }
class A, list1, это просто входящие данные - магия находится в Objects.hash (...) :)
источник
Objects.hash
выдает одно(v.a_1, v.b_1, v.c_1, v.d_1)
и(v.a_2, v.b_2, v.c_2, v.d_2)
то же значение для и , то они будут считаться равными и удаляться как дубликаты, без фактической проверки того, что a, b, c и d совпадают. Это может быть приемлемым риском, или вы можете захотеть использовать функцию, отличную от той,Objects.hash
которая гарантированно даст уникальный результат в вашем домене.Вам нужно использовать идиомы java 8 (steam)? Возможно, простое решение - перенести сложность в структуру данных, подобную карте, которая содержит числа в качестве ключа (без повторения) и время, когда оно встречается в качестве значения. Вы можете перебирать эту карту и делать что-то только с теми числами, которые ocurrs> 1.
import java.lang.Math; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.HashMap; import java.util.Iterator; public class RemoveDuplicates { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(new Integer[]{1,2,1,3,4,4}); Map<Integer,Integer> countByNumber = new HashMap<Integer,Integer>(); for(Integer n:numbers) { Integer count = countByNumber.get(n); if (count != null) { countByNumber.put(n,count + 1); } else { countByNumber.put(n,1); } } System.out.println(countByNumber); Iterator it = countByNumber.entrySet().iterator(); while (it.hasNext()) { Map.Entry pair = (Map.Entry)it.next(); System.out.println(pair.getKey() + " = " + pair.getValue()); } } }
источник
Попробуйте это решение:
public class Anagramm { public static boolean isAnagramLetters(String word, String anagramm) { if (anagramm.isEmpty()) { return false; } Map<Character, Integer> mapExistString = CharCountMap(word); Map<Character, Integer> mapCheckString = CharCountMap(anagramm); return enoughLetters(mapExistString, mapCheckString); } private static Map<Character, Integer> CharCountMap(String chars) { HashMap<Character, Integer> charCountMap = new HashMap<Character, Integer>(); for (char c : chars.toCharArray()) { if (charCountMap.containsKey(c)) { charCountMap.put(c, charCountMap.get(c) + 1); } else { charCountMap.put(c, 1); } } return charCountMap; } static boolean enoughLetters(Map<Character, Integer> mapExistString, Map<Character,Integer> mapCheckString) { for( Entry<Character, Integer> e : mapCheckString.entrySet() ) { Character letter = e.getKey(); Integer available = mapExistString.get(letter); if (available == null || e.getValue() > available) return false; } return true; } }
источник
А как насчет проверки индексов?
источник