如何在Java 8中合并两个Map of Map of Lists(Map<String,Map<Enum,List<String>>>)?

3
给定: 一个包含水果的映射表
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"}]
]

同样地,另一个包含蔬菜的映射

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"}]
]

我正在尝试将水果篮子 fruitBasket 和蔬菜篮子 veggieBasket 合并。

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,我在思考是否有更好/优化的方法来处理这个问题?
3个回答

2
您可以这样做:
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; }
                   )
               );

1
为什么不尝试将合并解决为以下方式:
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;
        }));

3
因为它是一个“singletonMap - 不可变”的对象。 - Pavan Kumar Jorrigala
@HadiJ 是的,在回答中进行了编辑。感谢您指出。 - Naman

0

你需要创建可修改的列表来合并重复的键。

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=[香蕉,橙子]},{VEGGIES=[马铃薯,西红柿]}],

basket2=[{FRUITS=[橙子,猕猴桃]},{VEGGIES=[洋葱,马铃薯]}],

basket1=[{FRUITS=[苹果,香蕉]},{VEGGIES=[西红柿,洋葱]}]}


你的解决方案的返回类型是什么? - Naman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接