Java 8,Streams查找重复元素

时间:2014-12-28 14:19:56

标签: java lambda java-8 java-stream

我试图列出整数列表中的重复元素,例如

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

使用jdk的Streams 8.是否有人尝试过。要删除重复项,我们可以使用distinct()api。但是如何找到重复的元素呢?有人可以帮帮我吗?

15 个答案:

答案 0 :(得分:97)

您可以使用Collections.frequency

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

答案 1 :(得分:38)

您需要一个集合(下面为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]

答案 2 :(得分:20)

基本示例。上半部分构建频率图,后半部分将其缩小为过滤列表。可能不如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() );

答案 3 :(得分:11)

我的StreamEx库增强了Java 8流,它提供了一个特殊的操作distinct(atLeast),它只能保留至少出现指定次数的元素。所以你的问题可以这样解决:

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

在内部,它类似于@Dave解决方案,它会计算对象,支持其他需要的数量,并且它是并行友好的(它使用ConcurrentHashMap用于并行化流,但是{{1}对于顺序)。对于大量数据,您可以使用HashMap获得加速。

答案 4 :(得分:8)

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

这种方法的空间复杂性会增加一倍,但这个空间不是浪费;事实上,我们现在只将副本作为一个集合以及另一个集合,同时删除所有重复项。

答案 5 :(得分:4)

您可以像这样重复:

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

答案 6 :(得分:3)

我认为该问题的基本解决方法如下:

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

好吧,不建议执行过滤器操作,但是为了更好的理解,我已经使用过它,此外,将来的版本中应该进行一些自定义过滤。

答案 7 :(得分:1)

多重集是一种结构,用于维护每个元素的出现次数。使用Guava实现:

CaracteristicA

答案 8 :(得分:1)

创建其他地图或流非常耗时且耗费空间……

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]


...,对于这个问题,我们声称是 [duplicate]

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

答案 9 :(得分:0)

我认为我有很好的解决方法如何修复这样的问题 - List =&gt;列出由Something.a&amp;组成的分组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(...)中:)

答案 10 :(得分:0)

你必须使用java 8成语(steams)吗? Perphaps一个简单的解决方案是将复杂性转移到类似地图的数据结构,该数据结构将数字保存为关键(不重复),并将数字作为值显示。你可以让他们迭代那个地图,只做那些与ocurrs的数字有关的事情&gt; 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());
    }
  }
}

答案 11 :(得分:0)

试试这个解决方案:

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

}

答案 12 :(得分:0)

如何检查索引?

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

答案 13 :(得分:0)

如果只需要检测重复项(而不是列出重复项,而这正是OP想要的),只需将它们转换为列表和集合,然后比较大小即可:

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

我喜欢这种方法,因为它很少出现错误。

答案 14 :(得分:0)

如果您正在寻找性能,

Set.add() 会更快。

public class FindDuplicatedBySet {

public static void main(String[] args) {
    List<Integer> list = Arrays.asList(5, 3, 4, 1, 3, 7, 2,3,1, 9, 9, 4,1);
    Set<Integer> result = findDuplicatedBySetAdd(list);
    result.forEach(System.out::println);
  }

public static <T> Set<T> findDuplicatedBySetAdd(List<T> list) {
    Set<T> items = new HashSet<>();
    return list.stream()
            .filter(n -> !items.add(n))
            .collect(Collectors.toSet());
  }
}