转换 Map<K, V> 为 Map<V,List<K>>

2022-09-03 13:02:31

我有如下地图

Map<String, String> values = new HashMap<String, String>();
values.put("aa", "20");
values.put("bb", "30");
values.put("cc", "20");
values.put("dd", "45");
values.put("ee", "35");
values.put("ff", "35");
values.put("gg", "20");

我想以格式创建新地图,示例输出将作为Map<String,List<String>>

"20" -> ["aa","cc","gg"]
"30" -> ["bb"]
"35" -> ["ee","ff"]     
"45" -> ["dd"]

我能够通过迭代实体来做

Map<String, List<String>> output = new HashMap<String,List<String>>();
    for(Map.Entry<String, String> entry : values.entrySet()) {
        if(output.containsKey(entry.getValue())){
            output.get(entry.getValue()).add(entry.getKey());

        }else{
            List<String> list = new ArrayList<String>();
            list.add(entry.getKey());
            output.put(entry.getValue(),list);
          }
    }

使用流可以更好地做到这一点吗?


答案 1

groupingBy可用于按值对键进行分组。如果不带 a 使用,它会将映射条目 () 的 a 转换为 a ,这接近您想要的,但并不完全如此。mappingCollectorStreamStream<Map.Entry<String,String>>Map<String,List<Map.Entry<String,String>>

为了使输出的值成为原始键的 a,必须将 a 链接到 .MapListmappingCollectorgroupingByCollector

Map<String,List<String>> output =
    values.entrySet()
          .stream()
          .collect(Collectors.groupingBy(Map.Entry::getValue,
                                         Collectors.mapping(Map.Entry::getKey,
                                                            Collectors.toList())));
System.out.println (output);

输出:

{45=[dd], 35=[ee, ff], 30=[bb], 20=[aa, cc, gg]}

答案 2

请注意,在 Java 8 中,您也可以在不使用 Map.forEach Map.computeIfAbsent 的流的情况下做得更好。这样,它比带有 ,等的旧版本更简洁。Map.Entry<String, String>entry.getValue()entry.getKey()

因此,您不必将旧的Java-7迭代与Java-8流解决方案进行比较,而是与此解决方案进行比较。

values.forEach( (key,value)->
    groupBy.computeIfAbsent(value, x->new ArrayList<>())
           .add(key)
);

推荐