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

Java 8, Потоки для поиска дублирующих элементов

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

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

Вам понадобится набор (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]

Ответ 3

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

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

Ответ 4

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

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

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

Ответ 5

Способ 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());

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

Ответ 6

Вы можете получить дубликат следующим образом:

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

Ответ 7

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

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

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

Ответ 8

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

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

Ответ 9

создание дополнительной карты или потока является time- и занимает много места…

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

Ответ 10

Я думаю, что у меня есть хорошее решение, как исправить такую ​​проблему: List = > List with group by 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(...):)

Ответ 11

Вы должны использовать 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());
    }
  }
}

Ответ 12

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

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

}

Ответ 13

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

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

Ответ 14

Если вам нужно только обнаружить наличие дубликатов (вместо того, чтобы перечислять их, чего и хотел ОП), просто конвертируйте их в список и набор, а затем сравните размеры:

    List<Integer> list = ...;
    Set<Integer> set = new HashSet<>(list);
    if (list.size() != set.size()) {
      // duplicates detected
    }

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