[java] Java 8, Streams에서 중복 요소 찾기

정수 목록에 중복 요소를 나열하려고합니다. 예를 들어,

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

jdk 8의 스트림을 사용하고 있습니다. 중복을 제거하기 위해 distinct () API를 사용할 수 있습니다. 하지만 중복 된 요소를 찾는 것은 어떻습니까? 아무도 나를 도울 수 있습니까?



답변

다음을 사용할 수 있습니다 Collections.frequency.

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


답변

기본 예. 전반부는 주파수 맵을 만들고 후반부는 필터링 된 목록으로 축소합니다. 아마도 Dave의 대답만큼 효율적이지는 않지만 더 다양합니다 (정확히 두 개를 감지하려는 경우 등).

     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]


답변

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

이 접근 방식에서는 공간 복잡성이 두 배가 될 것이지만 그 공간은 낭비가 아닙니다. 사실, 우리는 이제 모든 복제물도 제거 된 다른 세트뿐만 아니라 세트로만 복제 된 것을 가지고 있습니다.


답변

Java 8 스트림을 향상시키는 My StreamEx 라이브러리 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());


답변

질문에 대한 기본적인 해결책은 다음과 같습니다.

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

글쎄, 필터 작업을 수행하는 것은 권장되지 않지만 더 나은 이해를 위해 사용했으며 향후 버전에는 사용자 지정 필터링이 있어야합니다.