如何使用Java Stream的Filter与Collectors.toMap筛选不区分大小写的重复数据结构
解决大小写敏感重复项筛选的Stream实现方案
看起来你已经搞定了暴力解法,但想要更优雅的Stream实现对吧?问题出在你之前的filter条件没精准匹配需求——我们需要先过滤内层Map中符合条件的条目,再保留那些内层Map不为空的外层条目,而不是直接对整个内层Map做判断。
正确的Stream实现逻辑
我们需要分两步处理:
- 对于每个外层的
Integer -> Map<String, Set<String>>条目,先把内层Map中Set.size() > 1的键值对筛选出来,生成一个新的内层Map - 只保留那些新生成的内层Map不为空的外层条目(避免保留没有重复项的Integer分类)
修正后的代码替换原有的Stream部分
把你原来的Stream代码替换成下面这段:
Map<Integer, Map<String, Set<String>>> dupsAllTypes = caseInsensitiveDuplicates .entrySet() .stream() // 对每个外层条目,处理内层Map:筛选出Set大小>1的项 .map(entry -> { Map<String, Set<String>> filteredInnerMap = entry.getValue() .entrySet() .stream() .filter(innerEntry -> innerEntry.getValue().size() > 1) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); return Map.entry(entry.getKey(), filteredInnerMap); }) // 只保留内层Map不为空的外层条目 .filter(entry -> !entry.getValue().isEmpty()) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
为什么之前的条件不对?
- 第一个条件
e -> e.getValue().values().size() > 1:这个判断的是内层Map的键值对数量,而不是每个Set的大小,所以不管Set里有没有重复,只要内层Map有多个条目就会保留,显然不符合需求。 - 第二个条件
e -> e.getValue().values().stream().allMatch(set -> set.size() > 1):这个要求内层Map里所有的Set都必须有重复项,但你的例子里N2的Set只有一个元素,所以整个Integer=1的条目被过滤掉了,结果为空。
测试验证
替换后运行你的测试代码,输出会是:
caseInsensitiveDuplicates.keySet().size(): 1 t1Dups.keySet().size(): 2 k: N1 v: N1 v: n1 k: N2 v: n2 N1 size: 2 N2 size: 1 --- k:N1 v:N1 v:n1
完全符合你期望的结果:只保留了N1对应的条目。
额外优化(可选)
如果你的内层Map需要保持原有的有序性(比如你用了TreeMap),可以在Collectors.toMap里指定Map的实现类,比如:
.collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (oldVal, newVal) -> oldVal, // 合并策略,这里不会触发 TreeMap::new ));
这样生成的内层Map依然是TreeMap,保持排序。
内容的提问来源于stack exchange,提问作者JGFMK
相关产品推荐
相关产品推荐

