如何使用Java Streams将Map列表转换为列表映射

huangapple go评论59阅读模式
英文:

How to convert List of Map into Map of List using Java Streams

问题

我有一个List,其中包含Map,如下所示:

[{"a":"10","b":"20"},{"a":"12","b":"22"},{"a":"14","b":"24"}]

我想要一个Map,如下所示:

{"a":["10","12","14"],"b":["20","22","24"]}
英文:

I have List of Maps as

[{"a"="10","b"="20"},{"a"="12","b"="22"},{"a"="14","b"="24"}]

And I want a Map as

{"a"=["10","12","14"],"b"=["20","22","24"]}

答案1

得分: 7

你可以在不需要实例化额外数据结构的情况下完成这个任务。首先将Map映射为Map.Entry,然后按键分组。

var listOfMaps = List.of(
        Map.of("a", 10, "b", 20),
        Map.of("a", 12, "b", 22),
        Map.of("a", 14, "b", 24)
);

var mapOfLists = listOfMaps.stream()
        .map(Map::entrySet)
        .flatMap(Set::stream)
        .collect(Collectors.groupingBy(
                Map.Entry::getKey,
                Collectors.mapping(
                        Map.Entry::getValue,
                        Collectors.toList()
                )
        ));

System.out.println(mapOfLists);

输出:
{a=[10, 12, 14], b=[20, 22, 24]}

英文:

You can do this without having to instantiate an additional data structure. You first map the Maps to Map.Entry and then group by key.

var listOfMaps = List.of(
        Map.of("a", 10, "b", 20),
        Map.of("a", 12, "b", 22),
        Map.of("a", 14, "b", 24)
);

var mapOfLists = listOfMaps.stream()
        .map(Map::entrySet)
        .flatMap(Set::stream)
        .collect(Collectors.groupingBy(
                Map.Entry::getKey,
                Collectors.mapping(
                        Map.Entry::getValue,
                        Collectors.toList()
                )
        ));

System.out.println(mapOfLists);

Output:
{a=[10, 12, 14], b=[20, 22, 24]}

答案2

得分: 4

你可以使用Group By来实现这个目标。以下是一个示例。

首先,我们使用list.stream()获取一个列表的流,然后使用flatMap将每个Map的条目转换为流。现在我们有了每个条目(键-值对)的流,我们使用groupingBy将它们收集为一组。

groupingBy的第一个参数是用于派生键的函数,第二个参数是可选的,它是一个地图工厂,用于创建地图,如果您想要一个排序的地图,可以使用TreeMap::new。现在第三个参数是reducer部分,您告诉它将被分组的值以及如何收集它们(在我们的情况下,我们希望它们成为一个列表)。

Map<String, String> ma = new java.util.HashMap<>();
ma.put("a", "10");
ma.put("b", "20");
Map<String, String> ma3 = new java.util.HashMap<>();
ma3.put("a", "15");
ma3.put("b", "17");
ma3.put("c", "19");

List<Map<String, String>> list = Arrays.asList(ma, ma3);

Map<String, List<String>> lm = list.stream()
        .flatMap(x -> x.entrySet().stream())
        .collect(Collectors.groupingBy(
            Entry::getKey,
            HashMap::new,
            Collectors.mapping(Entry::getValue, Collectors.toList())
        ));

System.out.println(lm);

输出看起来像这样:

{a=[10, 15], b=[20, 17], c=[19]}
英文:

You can make use of Group By to achieve this. Here is an example.

First we take a stream of list using list.stream() and then we make a stream of each Map's Entry using flatMap. Now that we have a stream of each Entry(Key-value pair), we use groupingBy to collect them as a group.

First argument of groupingBy is functions what derive the key , Second argument is optional its a map factory which will be used to create the map, in case you want to have a sorted map you can use TreeMap::new , Now third param is reducer part where you tell what will be the grouped value and how it has to be collected(in our case we want it into a list)

Map&lt;String, String&gt; ma = new java.util.HashMap&lt;&gt;();
	ma.put(&quot;a&quot;, &quot;10&quot;);
	ma.put(&quot;b&quot;, &quot;20&quot;);
	Map&lt;String, String&gt; ma3 = new java.util.HashMap&lt;&gt;();
	ma3.put(&quot;a&quot;, &quot;15&quot;);
	ma3.put(&quot;b&quot;, &quot;17&quot;);
	ma3.put(&quot;c&quot;, &quot;19&quot;);

	List&lt;Map&lt;String, String&gt;&gt; list = Arrays.asList(ma, ma3);

	Map&lt;String, List&lt;String&gt;&gt; lm = list.stream().flatMap(x -&gt; x.entrySet().stream()).collect(Collectors
			.groupingBy(Entry::getKey, HashMap::new, Collectors.mapping(Entry::getValue, Collectors.toList())));

	System.out.println(lm);

Output looks like

{a=[10, 15], b=[20, 17], c=[19]}

答案3

得分: 3

Map<String, List<String>> map = new HashMap<>();
list.stream().flatMap(map -> map.entrySet().stream()).forEach(entry -> {
    map.putIfAbsent(entry.getKey(), new ArrayList<>());
    map.get(entry.getKey()).add(entry.getValue());
});

这段代码的目的是将一个包含多个内部MapList转换为一个包含相同键的Map,其中每个键关联一个值列表。

它不是一个单行代码,因为在forEach中需要两个语句,我不喜欢将这样的代码写成一行,但是提问者没有要求一行代码。

代码首先将内部Map的所有条目作为Stream获取(使用flatMap)。

然后,它对这些条目进行迭代,执行两个操作:

  • 如果条目值的List不存在,则添加一个新的空列表。
  • 将条目的值添加到条目的内部列表中。
英文:
Map&lt;String,List&lt;String&gt;&gt; map=new HashMap&lt;&gt;();
list.stream().flatMap(map-&gt;map.entrySet().stream()).forEach(entry-&gt;{
    map.putIfAbsent(entry.getKey(),new ArrayList&lt;&gt;());
    map.get(entry.getKey()).add(entry.getValue());
});

It is not a one-liner because I needed two statements in the forEach and I don't like to put something like that in one line but the OP did not ask for a one-liner.

It gets all entries of the inner Map as a Stream at first (flatMap).

After that, it iterates over them doing two actions:

  • If no List exists for the entry value, a new one is added.

  • The value of the entry is added to the inner list of the entry.

答案4

得分: 2

你可以在 Map#merge 中使用重新映射功能。

final Map<String, List<String>> result = new HashMap<>();
maps.forEach(map -> map.entrySet().forEach(entry ->
    result.merge(entry.getKey(), Arrays.asList(entry.getValue()),
        (a, b) -> Stream.concat(a.stream(), b.stream()).collect(Collectors.toList()))));
英文:

You can make use of the remapping function in Map#merge.

final Map&lt;String,List&lt;String&gt;&gt; result = new HashMap&lt;&gt;();
maps.forEach(map -&gt; map.entrySet().forEach(entry -&gt; 
    result.merge(entry.getKey(), Arrays.asList(entry.getValue()), 
        (a,b)-&gt;Stream.concat(a.stream(),b.stream()).collect(Collectors.toList()))));

huangapple
  • 本文由 发表于 2020年8月9日 01:05:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/63318102.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定