使用 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()
我正在尝试从整数列表中获取唯一重复的数字列表:
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()