【问题标题】:How do I generate a Map of Map of List (Map<String, Map<Enum, List<String>>>) in java using streamsjava - 如何使用流在java中生成列表映射(Map<String, Map<Enum, List<String>>>)
【发布时间】:2023-03-30 02:15:01
【问题描述】:

给定:

enum Food{
FRUITS, VEGGIES;
}

Map<String, List<String>> basketMap = new HashMap<>();
basketMap .put("bucket1", Arrays.asList("apple", "banana"));
basketMap .put("bucket2", Arrays.asList("orange", "kiwi"));
basketMap .put("bucket3", Arrays.asList("banana", "orange"));

需要生成list的map(popultefruitBaskerMap)

Map<String, Map<Food, List<String>> fruitBasketMap = new HashMap<>();

最终输出:

fruitBasketMap:
[
bucket1, [Food.FRUITS, {"apple", "banana"}],
bucket2, [Food.FRUITS, {"orange", "kiwi"}],
bucket3, [Food.FRUITS, {"banana", "orange"}]
]

我尝试了以下(但没有成功)

fruitBasketMap = basketMap.entrySet().stream().collect(
    Collectors.toMap(Map.Entry::getKey,
        Collectors.toMap(Food.FRUITS,
            Collectors.toList(Map.Entry::getValue())
        )
    )
);

谁能告诉我该怎么做?

【问题讨论】:

  • 您的代码的预期结果是什么?那张地图应该怎么填?它会包含任何蔬菜吗?
  • 不,您不需要生成Map&lt;String, Map&lt;Food, List&lt;String&gt;&gt;。您需要创建一个类,并将类型更改为Map&lt;String, ClassType&gt;
  • @Pshemo 它永远不会包含蔬菜,它只包含水果。刚刚更新了帖子并添加了预期的最终输出。
  • 您真的仅限于 Java 8 还是 Java 9 或更高版本的方法也可用?例如Map.of 会让你写像Collectors .toMap( Map.Entry::getKey, entry -&gt; Map.of(Food.FRUITS, entry.getValue()) ) 这样的收集器
  • 如果您仅限于 Java 8 而不是entry -&gt; Map.of(...),您可以使用entry -&gt; { Map&lt;Food, List&lt;String&gt;&gt; map = new HashMap&lt;&gt;(); map.put(Food.FRUITS, entry.getValue()); return map; }

标签: java collections java-8 java-stream


【解决方案1】:

这个实现似乎正在运行(使用 Java 9 Map.of):

Map<String, Map<Food, List<String>>> fruitBasketMap = basketMap.entrySet().stream()
        .map(e -> Map.entry(e.getKey(), Map.of(Food.FRUITS, e.getValue())))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

测试输出:

{
bucket2={FRUITS=[orange, kiwi]}, 
bucket3={FRUITS=[banana, orange]}, 
bucket1={FRUITS=[apple, banana]}
}

【讨论】:

  • This implementation seems to be working - 它确实可以工作?。
  • Map.of 是在 Java 9 中引入的,问题是用 Java 8 标记的,所以我不确定我们是否可以使用它。
【解决方案2】:

这应该以Java 8+ 的方式解决问题:

fruitBasketMap = 
    basketMap.entrySet()
             .stream()
             .collect(groupingBy(Entry::getKey,
                                 toMap(e -> Food.FRUITS, Entry::getValue)));

上述收集器的工作方式如下:

  1. 按元素的键对元素进行分组,因此键与原始地图中的键保持一致。
  2. 将条目收集到一个新映射中
    • 键:Food.FRUITS(所有条目的常量)
    • value:原始值(字符串列表)

【讨论】:

    【解决方案3】:

    这适用于 Java 8

    Map<String, Map<Food, List<String>>> collect = basketMap.entrySet().stream().collect(
                    Collectors.toMap(basketMapEntry -> basketMapEntry.getKey(),
                            basketMapEntry -> basketMapEntry.getValue().stream()
                                    .collect(Collectors.groupingBy(
                                            item -> type.get(item)
                                            )
                                    )
                    )
            );
    

    我正在使用 groupingBy 收集器根据枚举对项目列表进行分组。 假设会有一个 Map 来根据条目知道 Food 的值。比如:

    Map<String, Food> type = new HashMap<>();
            type.put("apple", Food.FRUITS);
            type.put("banana", Food.FRUITS);
            type.put("orange", Food.FRUITS);
            type.put("kiwi", Food.FRUITS);
            type.put("kiwi", Food.FRUITS);
            type.put("potato", Food.VEGGIES);
            type.put("carrot", Food.VEGGIES);
    

    【讨论】:

      【解决方案4】:

      您可以通过 Java-8 方式实现这一点。试试下面的一个。由于内部地图总是只有一个条目,您可以使用singletonMap

      Map<String, Map<Food, List<String>>> result = basketMap.entrySet()
                      .stream()
                      .collect(Collectors.toMap(Map.Entry::getKey, entry -> Collections.singletonMap(Food.FRUITS, entry.getValue())));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-01
        • 1970-01-01
        • 2018-08-02
        • 2020-01-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多