使用流转换和过滤 Java Map

新手上路,请多包涵

我有一个要转换和过滤的 Java 地图。作为一个简单的例子,假设我想将所有值转换为整数,然后删除奇数条目。

 Map<String, String> input = new HashMap<>();
input.put("a", "1234");
input.put("b", "2345");
input.put("c", "3456");
input.put("d", "4567");

Map<String, Integer> output = input.entrySet().stream()
        .collect(Collectors.toMap(
                Map.Entry::getKey,
                e -> Integer.parseInt(e.getValue())
        ))
        .entrySet().stream()
        .filter(e -> e.getValue() % 2 == 0)
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

System.out.println(output.toString());

这是正确的并产生: {a=1234, c=3456}

但是,我不禁想知道是否有办法避免调用 .entrySet().stream() 两次。

有没有一种方法可以同时执行转换和过滤操作,并在最后只调用一次 .collect()

原文由 Paul I 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 566
2 个回答

是的,您可以将每个条目映射到另一个临时条目,该条目将保存键和解析的整数值。然后您可以根据它们的值过滤每个条目。

 Map<String, Integer> output =
    input.entrySet()
         .stream()
         .map(e -> new AbstractMap.SimpleEntry<>(e.getKey(), Integer.valueOf(e.getValue())))
         .filter(e -> e.getValue() % 2 == 0)
         .collect(Collectors.toMap(
             Map.Entry::getKey,
             Map.Entry::getValue
         ));

请注意,我使用了 Integer.valueOf 而不是 parseInt 因为我们实际上想要一个盒装的 int


如果你有幸使用 StreamEx 库,你可以很简单地做到这一点:

 Map<String, Integer> output =
    EntryStream.of(input).mapValues(Integer::valueOf).filterValues(v -> v % 2 == 0).toMap();

原文由 Tunaki 发布,翻译遵循 CC BY-SA 3.0 许可协议

以更少的开销解决问题的一种方法是将映射和过滤向下移动到收集器。

 Map<String, Integer> output = input.entrySet().stream().collect(
    HashMap::new,
    (map,e)->{ int i=Integer.parseInt(e.getValue()); if(i%2==0) map.put(e.getKey(), i); },
    Map::putAll);

这不需要创建中间 Map.Entry 实例甚至更好,将推迟 int 值的装箱到实际将值添加到 Map ,这意味着过滤器拒绝的值根本没有装箱。

Collectors.toMap(…) 相比,操作也通过使用 Map.put 而不是 Map.merge 得到简化,因为我们事先知道我们必须在这里处理密钥冲突.

但是,只要您不想使用并行执行,您也可以考虑普通循环

HashMap<String,Integer> output=new HashMap<>();
for(Map.Entry<String, String> e: input.entrySet()) {
    int i = Integer.parseInt(e.getValue());
    if(i%2==0) output.put(e.getKey(), i);
}

或内部迭代变体:

 HashMap<String,Integer> output=new HashMap<>();
input.forEach((k,v)->{ int i = Integer.parseInt(v); if(i%2==0) output.put(k, i); });

后者非常紧凑,至少与单线程性能方面的所有其他变体相当。

原文由 Holger 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题