【问题标题】:Convert a list of maps to a map of lists using Java Streams使用 Java Streams 将映射列表转换为列表映射
【发布时间】:2021-02-16 09:30:11
【问题描述】:

我想将地图列表转换为列表地图。保证所有的地图都有相同的键。

例如下面的列表

[{key1: val1, key2: val2}, {key1: val3, key2: val4}]

转换成

{key1: [val1, val3], key2: [val2, val4]}

下面的代码使用for循环来实现

List<Map<String, Object>> data = getData();

Map<String, List<Object>> result = new HashMap<>();

for (Map<String, Object> element: data) {
    element.forEach((key, val) -> {
        if (result.containsKey(key))
            result.get(key).add(val);
        else
            result.put(key, Arrays.asList(val));
    });
}

如何使用流实现相同的结果?

【问题讨论】:

    标签: java list dictionary java-stream


    【解决方案1】:

    例如像这样,依赖于java流的collect阶段。

    List<Map<String, Object>> data = new ArrayList<>();
    
    HashMap<String, List<Object>> transposed = data.stream()
            .flatMap(i -> i.entrySet().stream())
            .collect(Collectors.groupingBy(
                    Map.Entry::getKey,
                    HashMap::new,
                    Collectors.mapping(Map.Entry::getValue,
                            Collectors.toCollection(ArrayList::new))));
    

    在 SO 上有许多这样的应用程序(例如 this one),但并不完全针对这个例子。

    【讨论】:

      【解决方案2】:

      你可以使用Collectors.toMap方法:

      List<Map<String, String>> listOfMaps = List.of(
              Map.of("key1", "val1", "key2", "val2"),
              Map.of("key1", "val3", "key2", "val4"));
      
      Map<String, List<String>> mapOfLists = listOfMaps.stream()
              // Stream<Map<String,String>>
              .flatMap(map -> map.entrySet().stream())
              // Stream<Map.Entry<String,String>>
              .collect(Collectors.toMap(
                      // key
                      Map.Entry::getKey,
                      // value
                      e -> List.of(e.getValue()),
                      // merge function
                      (list1, list2) -> {
                          List<String> list = new ArrayList<>();
                          list.addAll(list1);
                          list.addAll(list2);
                          return list;
                      }, // map factory
                      LinkedHashMap::new));
      
      System.out.println(listOfMaps);
      // [{key1=val1, key2=val2}, {key1=val3, key2=val4}]
      System.out.println(mapOfLists);
      // {key1=[val1, val3], key2=[val2, val4]}
      

      另见:Convert a map of lists into a list of maps

      【讨论】:

        【解决方案3】:

        这个依赖stream.reduce的版本应该可以做到:

        // some values for testing
        List<Map<String, Object>> list = new ArrayList<>();
        list.add(Map.of("1", "One", "2", "Two"));
        list.add(Map.of("3", "Three", "4", "Four", "5", "Five"));
        list.add(Map.of("3", "Teen", "5", "Penta"));
        list.add(Map.of("3", "Trice", "4", "Quattro"));
        
        // conversion with stream reduction
        Map<String, List<Object>> result = list.stream().reduce(new HashMap<>(),
                (acc, map) -> {
                    map.forEach((k, v) -> acc.computeIfAbsent(k,
                            l -> new ArrayList<Object>()).add(v));
                    return acc;
                },
                (acc1, acc2) -> {
                    acc1.putAll(acc2);
                    return acc1;
                });
        
        // output
        System.out.println(result);
        //{1=[One], 2=[Two], 3=[Three, Teen, Trice], 4=[Four, Quattro], 5=[Five, Penta]}
        

        解释:此代码遍历列表中的每个映射并将其累积到哈希映射(reduce 函数的第一个参数)中,累积函数(第二个参数)将一个新列表添加到hashmap 如果它第一次看到一个键(否则它会累积在已经存在的列表中);第三个函数是串行或并行运行流函数之间的一致性所必需的(它在并行运行中结合部分结果)。

        【讨论】:

          【解决方案4】:

          您可以在没有流的情况下以现代方式做到这一点,如下所示:

          Map<String, List<Object>> result = new HashMap<>();
          data.forEach(element -> 
              element.forEach((k, v) - > 
                  result.computeIfAbsent(k, x -> new ArrayList<>()).add(v)));
          

          这会迭代列表和每个映射,并使用Map.computeIfAbsent 来容纳result 映射中的条目。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-10-02
            • 2011-10-23
            • 1970-01-01
            • 2019-01-19
            相关资源
            最近更新 更多