如何根据出现次数过滤条目?
How can I filter entries based on occurrence count?
使用流 API,如何在使用 groupingBy
->counting
操作收集后过滤包含基于出现次数过滤器的条目?
鉴于以下情况:
Map<Integer, Long> counts = Stream.of(1, 2, 2, 3, 4, 5, 5)
.collect(groupingBy(n -> n, counting()));
如何将其过滤为仅包含键 2
和 5
?
我可以使用以下内容,但我希望能够继续流而不需要先收集。
Map<Integer, Long> counts = Stream.of(1, 2, 2, 3, 4, 5, 5)
.collect(groupingBy(n -> n, counting()))
.entrySet().stream()
.filter(n -> n.getValue() > 1)
.collect(toMap(Entry::getKey, Entry::getValue));
没有办法为依赖于已见值的操作构建映射或类似数据结构。这与例如 distinct
相同,它看起来像是操作链中的一个步骤,但如果不在内部构建地图(或类似地图的结构)就无法工作。
您可以使用
使整个事情看起来像单个流操作
Map<Integer, Long> counts = Stream.of(1, 2, 2, 3, 4, 5, 5)
.collect(collectingAndThen(groupingBy(n -> n, counting()),
map -> map.entrySet().stream()
.filter(n -> n.getValue() > 1)
.collect(toMap(Entry::getKey, Entry::getValue))
));
但这不会改变它的工作方式。请记住,必须首先记住每个遇到的值,因为它需要到达流的末尾才能推断出不存在该值的其他出现。
请注意,有时非流操作可能看起来更简洁:
Map<Integer, Long> counts = Stream.of(1, 2, 2, 3, 4, 5, 5)
.collect(groupingBy(n -> n, HashMap::new, counting()));
counts.values().removeIf(count -> count < 2);
如果您有兴趣在(支持并行的)Stream
中处理项目本身而不关心实际出现次数,这里有一个简单的解决方案:
ConcurrentHashMap<Integer,Integer> counts=new ConcurrentHashMap<>();
Stream.of(1, 2, 2, 3, 4, 5, 5)
.filter(i -> counts.merge(i, 1, Integer::sum)==2)
.forEach(System.out::println);
它允许在遇到第二个项目时立即将后续操作应用到终端操作,而无需处理所有项目或等待流结束并与 parallel
执行and/or短路操作如limit
或findAny
等
使用流 API,如何在使用 groupingBy
->counting
操作收集后过滤包含基于出现次数过滤器的条目?
鉴于以下情况:
Map<Integer, Long> counts = Stream.of(1, 2, 2, 3, 4, 5, 5)
.collect(groupingBy(n -> n, counting()));
如何将其过滤为仅包含键 2
和 5
?
我可以使用以下内容,但我希望能够继续流而不需要先收集。
Map<Integer, Long> counts = Stream.of(1, 2, 2, 3, 4, 5, 5)
.collect(groupingBy(n -> n, counting()))
.entrySet().stream()
.filter(n -> n.getValue() > 1)
.collect(toMap(Entry::getKey, Entry::getValue));
没有办法为依赖于已见值的操作构建映射或类似数据结构。这与例如 distinct
相同,它看起来像是操作链中的一个步骤,但如果不在内部构建地图(或类似地图的结构)就无法工作。
您可以使用
使整个事情看起来像单个流操作Map<Integer, Long> counts = Stream.of(1, 2, 2, 3, 4, 5, 5)
.collect(collectingAndThen(groupingBy(n -> n, counting()),
map -> map.entrySet().stream()
.filter(n -> n.getValue() > 1)
.collect(toMap(Entry::getKey, Entry::getValue))
));
但这不会改变它的工作方式。请记住,必须首先记住每个遇到的值,因为它需要到达流的末尾才能推断出不存在该值的其他出现。
请注意,有时非流操作可能看起来更简洁:
Map<Integer, Long> counts = Stream.of(1, 2, 2, 3, 4, 5, 5)
.collect(groupingBy(n -> n, HashMap::new, counting()));
counts.values().removeIf(count -> count < 2);
如果您有兴趣在(支持并行的)Stream
中处理项目本身而不关心实际出现次数,这里有一个简单的解决方案:
ConcurrentHashMap<Integer,Integer> counts=new ConcurrentHashMap<>();
Stream.of(1, 2, 2, 3, 4, 5, 5)
.filter(i -> counts.merge(i, 1, Integer::sum)==2)
.forEach(System.out::println);
它允许在遇到第二个项目时立即将后续操作应用到终端操作,而无需处理所有项目或等待流结束并与 parallel
执行and/or短路操作如limit
或findAny
等