【问题标题】:How do I Combine/Merge two Map of Map of Lists (Map<String, Map<Enum, List<String>>>) in Java 8如何在 Java 8 中合并/合并两个列表映射(Map<String,Map<Enum,List<String>>>)
【发布时间】:2020-04-22 15:41:30
【问题描述】:

鉴于: 包含水果的地图

enum Food{
FRUITS, VEGGIES;
}

Map<String, Map<Food, List<String>>> fruitBasket= new HashMap<>();
fruitBasket.put("basket1", Collections.singletonMap(Food.FRUITS, Arrays.asList("apple","banana")));
fruitBasket.put("basket2", Collections.singletonMap(Food.FRUITS, Arrays.asList"orange", "kiwi")));
fruitBasket.put("basket3", Collections.singletonMap(Food.FRUITS, Arrays.asList("banana", "orange")));

fruitBasket:
[
basket1, [Food.FRUITS, {"apple", "banana"}],
basket2, [Food.FRUITS, {"orange", "kiwi"}],
basket3, [Food.FRUITS, {"banana", "orange"}]
]

同样是另一张包含 VEGGIES 的地图

Map<String, Map<Food, List<String>>> veggieBasket= new HashMap<>();
veggieBasket.put("basket1", Collections.singletonMap(Food.VEGGIES, Arrays.asList("Tomato","Onion")));
veggieBasket.put("basket2", Collections.singletonMap(Food.VEGGIES, Arrays.asList("Onion", "Potato")));
veggieBasket.put("basket3", Collections.singletonMap(Food.VEGGIES, Arrays.asList("Potato", "Tomato")));

veggieBasket:
[
basket1, [Food.VEGGIES, {"Tomato","Onion"}],
basket2, [Food.VEGGIES, {"Onion", "Potato"}],
basket3, [Food.VEGGIES, {"Potato", "Tomato"}]
]

我正在尝试组合篮子 fruitBasketveggieBasket

Final output: should look something like below

groceryBasket
[
basket1, [Food.FRUITS, {"apple", "banana"}, Food.VEGGIES, {"Tomato","Onion"}],
basket2, [Food.FRUITS, {"orange", "kiwi"}, Food.VEGGIES, {"Onion", "Potato"}],
basket3, [Food.FRUITS, {"banana", "orange"}, Food.VEGGIES, {"Potato", "Tomato"}]
]

我的解决方案:

Solution 1:
Map<String, Map<Food, List<String>>> groceryBasket= new HashMap<>();

grocery basket = Stream.concat(fruitBasket.entrySet().stream(), veggieBasket.entrySet().stream())
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (fruitList, veggieList ) ->
                {
                    final List<String> groceryList = new ArrayList<>();
                    groceryList .addAll(fruitList);
                    groceryList .addAll(veggieList);
                    return groceryList;
                }));

Solution 2:
Map<String, Map<Food, List<String>>> groceryBasket= new HashMap<>();

grocery basket = Stream.concat(fruitBasket.entrySet().stream(), veggieBasket.entrySet().stream())
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (fruitList, veggieList ) ->
                {
                    return Stream.of(fruitList, veggieList).flatMap(x -> x.stream()).collect(Collectors.toList());
                }));

我尝试了解决方案 1 和解决方案 2,我想知道是否有更好/优化的方法来处理这个问题?

【问题讨论】:

    标签: java collections java-8 java-stream


    【解决方案1】:

    你可以这样做:

    Map<String, Map<Food, List<String>>> groceryBasket = 
       Stream.concat(fruitBasket.entrySet().stream(),veggieBasket.entrySet().stream())
           .collect(Collectors.toMap(Map.Entry::getKey, v -> v.getValue().entrySet().stream()
                       .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)),
                        (a, b) -> { a.putAll(b);return a; }
                       )
                   );
    

    【讨论】:

      【解决方案2】:

      为什么不尝试将合并解析为:

      Map<String, Map<Food, List<String>>> groceryBasket =
              Stream.concat(fruitBasket.entrySet().stream(), veggieBasket.entrySet().stream())
                      .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> {
                          Map<Food, List<String>> innerMap = new HashMap<>(a);
                          innerMap.putAll(b);
                          return innerMap;
                      }));
      

      或者如果内部映射是可变的,那么稍微方便一点

      Map<String, Map<Food, List<String>>> groceryBasket = Stream.concat(fruitBasket.entrySet().stream(),
              veggieBasket.entrySet().stream())
              .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> {
                  a.putAll(b);
                  return a;
              }));
      

      【讨论】:

      • 因为它是singletonMap - immutable
      • @HadiJ 正确,已在答案中编辑。感谢您的指出。
      【解决方案3】:

      您必须创建可修改的列表来合并重复键,

      Stream.concat(fruitBasket.entrySet().stream(), veggieBasket.entrySet().stream())
                      .collect(Collectors.toMap(Map.Entry::getKey, e -> listOf(e.getValue()),
                              (left, right) -> {
                                  left.addAll(right);
                                  return left;
                              }));
      

      要创建可修改的列表,

      public static List<Map<Food, List<String>>> listOf(Map<Food, List<String>> a) {
          final ArrayList<Map<Food, List<String>>> list = new ArrayList<>();
          list.add(a);
          return list;
      }
      

      输出:

      {basket3=[{FRUITS=[香蕉,橙子]},{蔬菜=[土豆,番茄]}],

      basket2=[{FRUITS=[orange, kiwi]}, {VEGGIES=[Onion, Potato]}],

      basket1=[{FRUITS=[apple,banana]}, {VEGGIES=[Tomato, Onion]}]}

      【讨论】:

      • 您的解决方案的返回类型是什么?
      猜你喜欢
      • 2023-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-27
      • 1970-01-01
      • 1970-01-01
      • 2017-05-19
      • 1970-01-01
      相关资源
      最近更新 更多