使用 java 8 个流从重复整数列表中获取唯一编号

obtaining unique number from a list of duplicate integers using java 8 streams

我正在尝试从整数列表中获取唯一重复的数字列表:

final Set<Integer> setOfNmums = new HashSet<>();
Arrays.asList(5,6,7,7,7,6,2,4,2,4).stream()
        .peek(integer -> System.out.println("XX -> " + integer))
        .filter(n -> !setOfNmums.add(n))
        .peek(System.out::println)
        .map(String::valueOf)
        .sorted()
        .collect(Collectors.toList());
The output is 2,4,6,7,7 
Expected : 2,4,6,7

我不明白这是怎么回事..这是 运行 并行吗?我怎么得到两个“7”?

哈希集如果存在并且被过滤器使用,应该 return false?

是的,我可以使用 distinct,但我很想知道为什么过滤器会失败。它是并行完成的吗?

您可以在流中使用 .distinct() 函数 check this out.

您的过滤器拒绝每个元素的第一次出现并接受所有后续出现。因此,当一个元素出现 n 次时,您将添加它 n-1 次。

由于您想接受所有出现不止一次的元素,但只接受它们一次,您可以使用 .filter(n -> !setOfNmums.add(n)) .distinct() 或将集合增强为映射,以便能够接受一个元素仅在第二次出现时。

Map<Integer, Integer> occurrences = new HashMap<>();
List<String> result = Stream.of(5,6,7,7,7,6,2,4,2,4)
    .filter(n -> occurrences.merge(n, 1, Integer::sum) == 2)
    .map(String::valueOf)
    .sorted()
    .collect(Collectors.toList());

但一般来说,不鼓励对流使用有状态过滤器。

更清洁的解决方案是

List<String> result = Stream.of(5,6,7,7,7,6,2,4,2,4)
   .collect(Collectors.collectingAndThen(
      Collectors.toMap(String::valueOf, x -> true, (a,b) -> false, TreeMap::new),
      map -> { map.values().removeIf(b -> b); return new ArrayList<>(map.keySet()); }));

请注意,此方法不计算出现次数,而仅记住元素是唯一的还是至少出现过第二次。这通过使用 toMap 收集器 x -> true 的第二个参数将每个元素映射到 true 并使用 (a,b) -> false 的合并函数解决多次出现来实现。随后的 map.values().removeIf(b -> b) 将删除所有唯一元素,即映射到 true.

的元素

既然 Holger 已经解释了为什么你的解决方案不起作用,我将提供ide 一个替代方案。

为什么不将 Collections.frequency(collection, element)distinct() 一起使用?

解决方案非常简单(我为格式化道歉,我只是从我的 ide 中复制它并且 SOF 中似乎没有自动格式功能):

        List<Integer> numbers = List.of(5, 6, 7, 7, 7, 6, 2, 4, 2, 4);
        List<String> onlyDuplicates = numbers.stream()
                .filter(n -> Collections.frequency(numbers, n) > 1)
                .distinct()
                .sorted()
                .map(String::valueOf)
                .toList();

这只是保留所有出现不止一次的元素,然后在排序前过滤掉重复元素,将每个元素转换为字符串并收集到列表中,因为这似乎是您想要的。

如果你需要一个可变列表,你可以使用 collect(toCollection(ArrayList::new)) 而不是 toList()