【问题标题】:Java-8 Streams: Convert List<{String,List<String>}> to Map<String, List<String>>Java-8 流:将 List<{String,List<String>}> 转换为 Map<String, List<String>>
【发布时间】:2020-07-24 13:02:46
【问题描述】:

我有一个包含项目列表的标记类

class Tag {

private String tagName
private List<String> items

}

我有一个标签列表,其中每个标签都是一个项目列表

List<Tag> tagList =   [
                       {"tagName": "popular", "items": ["Item1","Item2","Item3","Item4"]},
                       {"tagName": "expensive" , "items":  ["Item2","Item4","Item5"]},
                       {"tagName": "mostwanted", "items":  ["Item1","Item2","Item5"]}
                      ]

我想把它转换成一个地图,其中项目作为键,标签名作为值。

预期输出:

{
    "Item1" : ["popular","mostwanted"],
    "Item2" : ["popular","expensive","mostwanted"],
    "Item3" : ["popular","mostwanted"],
    "Item4" : ["popular","expensive"],
    "Item5" : ["expensive","mostwanted"]
}

我尝试了 stream/faltmap/groupingBy 的各种组合,但没有得到预期的输出。你能帮忙吗?谢谢

【问题讨论】:

    标签: java java-8 java-stream grouping


    【解决方案1】:

    您可以使用flatMap 平展items,然后使用SimpleEntry 创建一对itemtagName。然后按item 分组,使用groupingBy 并映射tagName 以获取tagName 列表

    Map<String, List<String>> tagMap = tagList.stream()
            .flatMap(t -> t.getItems()
                           .stream()
                           .map(item -> new AbstractMap.SimpleEntry<>(item, t.getTagName())))
            .collect(Collectors.groupingBy(m -> m.getKey(),
                Collectors.mapping(m -> m.getValue(), Collectors.toList())));
    

    【讨论】:

    • 不错的!这里的 Stream API 看起来很笨拙 :) 而且,我很难编写它。
    • @Nikolas 如果您更喜欢 Stream API,那么它看起来也不错 :)
    【解决方案2】:

    这是使用 中的新功能(例如Map::computeIfPresentMap::computeIfAbsent,但不使用)的程序方法:

    Map<String, List<String>> map = new HashMap<>();
        tagList.forEach(tag -> {
            String tagName = tag.getTagName();
            tag.getItems().forEach(item -> {
                map.computeIfPresent(item, (k, v) -> { v.add(tagName); return v; });
                map.computeIfAbsent(item, k -> new ArrayList<>(Arrays.asList(tagName)));
       });
    });
    
    map.forEach((k, v) -> System.out.println(k + " " + v));
    

    如果要将这些项目从Item1 排序到Item5,请使用不同的实现:

    Map<String, List<String>> map = new TreeMap<>();
    

    此外,只要Item3 出现一次,您的预期输出就会不匹配:

    Item1 [popular, mostwanted]
    Item2 [popular, expensive, mostwanted]
    Item3 [popular]
    Item4 [popular, expensive]
    Item5 [expensive, mostwanted]
    

    【讨论】:

    • 你的意思可能是更简单的tagList.forEach(tag -&gt; tag.getItems().forEach(item -&gt; map.computeIfAbsent(item, k -&gt; new ArrayList&lt;&gt;()).add(tag.getTagName())));...虽然我更喜欢for (Tag tag : tagList) { for (String item : tag.getItems()) { map.computeIfAbsent(item, k -&gt; new ArrayList&lt;&gt;()) .add(tag.getTagName()); } }
    • @Naman:你说得对,我忘记了这些方法的返回类型(恕我直言,在我看来,“计算”这个词在某种程度上与 void 相关联)。随时发布您的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-17
    • 2018-09-06
    • 2021-02-28
    • 2020-04-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多