it-swarm.com.ru

Java 8, Потоки, чтобы найти дубликаты элементов

Я пытаюсь перечислить дубликаты элементов в целочисленном списке, например, например,

List<Integer> numbers = Arrays.asList(new Integer[]{1,2,1,3,4,4});    

используя потоки jdk 8. Кто-нибудь пробовал. Чтобы удалить дубликаты, мы можем использовать API различных (). Но как насчет поиска дублированных элементов? Кто-нибудь может мне помочь?

47
Siva

Вы можете использовать Collections.frequency :

numbers.stream().filter(i -> Collections.frequency(numbers, i) >1)
                .collect(Collectors.toSet()).forEach(System.out::println);
90
Bao Dinh

Вам нужен набор (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]
34
Dave

Основной пример. Первая половина строит карту частот, вторая половина сокращает ее до отфильтрованного списка. Вероятно, не так эффективно, как ответ Дейва, но более универсален (например, если вы хотите обнаружить ровно два и т.д.)

    List<Integer> duplicates = IntStream.of( 1, 2, 3, 2, 1, 2, 3, 4, 2, 2, 2 )
                                            .boxed()
                                            .collect( Collectors.groupingBy( c -> c, Collectors.counting() ) )
                                            .entrySet()
                                            .stream()
                                            .filter( p -> p.getValue() > 1 )
                                            .map( e -> e.getKey() )
                                            .collect( Collectors.toList() );
18
RobAu

My StreamEx библиотека, которая расширяет потоки Java 8, предоставляет специальную операцию distinct(atLeast) , которая может сохранять только элементы, появляющиеся как минимум указанное количество раз. Таким образом, ваша проблема может быть решена так:

List<Integer> repeatingNumbers = StreamEx.of(numbers).distinct(2).toList();

Внутренне он похож на решение @Dave, он подсчитывает объекты для поддержки других требуемых величин и является параллельным (он использует ConcurrentHashMap для распараллеленного потока, но HashMap для последовательного). Для больших объемов данных вы можете ускорить использование .parallel().distinct(2).

11
Tagir Valeev

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());

При таком подходе сложность пространства удваивается, но это пространство не является пустой тратой; по сути, теперь у нас есть только дублированный набор как набор, а также другой набор со всеми удаленными дубликатами.

8
Thomas Mathew

Вы можете получить дубликаты так:

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());
4
Oussama Zoghlami

Я думаю, что основные решения вопроса должны быть такими:

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());

ну, не рекомендуется выполнять операцию фильтра, но для лучшего понимания я ее использовал, более того, в будущих версиях должна быть некоторая пользовательская фильтрация.

3
Prashant

Мультимножество - это структура, поддерживающая количество вхождений для каждого элемента. Использование реализации Guava:

Set<Integer> duplicated =
        ImmutableMultiset.copyOf(numbers).entrySet().stream()
                .filter(entry -> entry.getCount() > 1)
                .map(Multiset.Entry::getElement)
                .collect(Collectors.toSet());
1
numéro6

Я думаю, что у меня есть хорошее решение, как решить проблему, как это - List => List с группировкой по 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);
    }

}

класс A, list1 это просто входящие данные - магия в Objects.hash (...) :)

0

Как насчет проверки индексов?

        numbers.stream()
            .filter(integer -> numbers.indexOf(integer) != numbers.lastIndexOf(integer))
            .collect(Collectors.toSet())
            .forEach(System.out::println);
0
bagom

Попробуйте это решение:

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;
}

}
0
Ilia Galperin

Вы должны использовать идиомы Java 8 (пары)? Возможно, простое решение состояло бы в том, чтобы переместить сложность в структуру данных, аналогичную карте, которая содержит числа в качестве ключа (без повторения) и время, в которое оно возникает в качестве значения. Вы можете повторить эту карту и сделать что-то только с теми числами, которые находятся в диапазоне> 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());
    }
  }
}
0
Victor