如何检查Java 8 Streams中是否存在任何重复?

ped*_*o91 45 java duplicates java-8 java-stream

在java 8中,检查List是否包含任何重复的最佳方法是什么?

我的想法是这样的:

list.size() != list.stream().distinct().count()
Run Code Online (Sandbox Code Playgroud)

这是最好的方式吗?

Psh*_*emo 47

您的代码需要遍历所有元素.如果你想确保没有重复的简单方法,比如

public static <T> boolean areAllUnique(List<T> list){
    Set<T> set = new HashSet<>();

    for (T t: list){
        if (!set.add(t))
            return false;
    }

    return true;
}
Run Code Online (Sandbox Code Playgroud)

会更有效率.

此方法也可以重写为(假设非并行流和线程安全的环境)

public static <T> boolean areAllUnique(List<T> list){
    Set<T> set = new HashSet<>();
    return list.stream().allMatch(t -> set.add(t));
}
Run Code Online (Sandbox Code Playgroud)

或者@Holger在评论中提到

public static <T> boolean areAllUnique(List<T> list){
    return list.stream().allMatch(new HashSet<>()::add);
}
Run Code Online (Sandbox Code Playgroud)

  • 这甚至可以是一行代码:`return list.stream().allMatch(new HashSet <>():: add);` (25认同)
  • 都.规范要求谓词是无状态的.关于并行运行的常见警告适用.ConcurrentHashMap可能有所帮助.可能还有其他问题,但我还没喝咖啡.:-) (8认同)
  • 在这里使用带有副作用的谓词似乎有点危险. (6认同)
  • @KorayTugay 当创建函数接口的实例(此处为“Predicate”)并在该对象的整个生命周期中重用时,“表达式::名称”形式的方法引用将评估“表达式”并捕获其结果。请参阅[System.out::println 的等效 lambda 表达式是什么](/sf/ask/1961635511/) 或[此问答](/sf/ask/2658581201/ )… (5认同)
  • @Stuart Marks:我认为,对于跨越"Stream"整个生命周期的单行,可以依靠程序员来识别该流是否是多线程的.当然,如果有疑问,使用`ConcurrentMap`可能会有所帮助.有状态的谓词可能不是最好的,但有时是不可避免的,不同的测试是*常见的例子.也许你还记得[这一个](http://stackoverflow.com/a/27872852/2711488); ^) (4认同)
  • 关于@StuartMarks关注的问题,或许会有一个简短的说明. (3认同)
  • @MubasharAhmad这不是*错*,但是`new HashSet <>(list)`将迭代整个`list`,而`.allMatch(new HashSet <>():: add)`是短路的,它会在第一次出现重复元素时返回`false`. (3认同)
  • @Holger哇,我从来没有这样做过.我每天都学到新东西:)谢谢! (2认同)
  • @Holger我当然记得.:-)但是使用有状态谓词需要一定程度的谨慎.我认为有人可能会将此代码复制并粘贴到不同的上下文中,而不了解其限制,并以此方式引入错误. (2认同)
  • @Holger 你能帮我理解一句台词是如何工作的吗?我可以看到如果我们有一个谓词引用的“最终 HashSet”,它会如何工作,但是为什么元素会以当前的方式添加到同一个 HashSet 中呢? (2认同)

Sas*_*sha 11

我使用了以下内容:
1 return list.size() == new HashSet<>(list).size();.

我不确定它与:
2.return list.size() == list.stream().distinct().count();

3. return list.stream().sequential().allMatch(new HashSet<>()::add);
在性能方面的比较.

最后一个(#3)不仅可以处理集合(例如列表),还可以处理流(没有明确地收集它们).

更新:最后一个(#3)似乎是最好的,不仅因为它可以处理纯流,而且因为它在第一个副本上停止(而#1和#2总是迭代直到结束) - 作为@Pshemo 评论说.


Wil*_*eys 6

您可以使用计数收集器。

Stream.of(1, 3, 4, 6, 7, 5, 6)
            .collect(Collectors.groupingBy(
                    Function.identity(), Collectors.counting()))
            .entrySet().stream().anyMatch(e -> e.getValue() > 1)
Run Code Online (Sandbox Code Playgroud)