我试图列出整数列表中重复的元素,例如:
List<Integer> numbers = Arrays.asList(new Integer[]{1,2,1,3,4,4});
使用JDK 8的Streams功能。有人尝试过吗?为了删除重复元素,我们可以使用distinct() API。但是如果想要查找重复的元素呢?有人能帮我吗?
我试图列出整数列表中重复的元素,例如:
List<Integer> numbers = Arrays.asList(new Integer[]{1,2,1,3,4,4});
使用JDK 8的Streams功能。有人尝试过吗?为了删除重复元素,我们可以使用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]
filter()
需要一个无状态谓词。你提供的“解决方案”与Java文档中给出的有状态谓词示例非常相似。参考链接:https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#Statelessness - Matt McHenrysequential()
时,这很可能是安全的。在更一般的情况下,流可能是parallel()
,那么很有可能会出现奇怪的错误。 - Matt McHenry一种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());
这种方法的空间复杂度会增加一倍,但这些空间并不浪费。实际上,我们现在有一个仅包含副本的Set,以及另一个删除了所有副本的Set。
我的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);
。 - Tagir Valeevstream
内部嵌套stream
会很昂贵。 - Vishwa Ratna我认为解决这个问题的基本方法应该如下:
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());
如果您只需要检测重复项是否存在(而不是列出它们,这是OP想要的),只需将它们转换为List和Set,然后比较大小:
List<Integer> list = ...;
Set<Integer> set = new HashSet<>(list);
if (list.size() != set.size()) {
// duplicates detected
}
我喜欢这种方法,因为它有更少的错误可能性。
创建额外的地图或流是耗费时间和空间的...
最初的回答
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() );
}