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

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

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

问题

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

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

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

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

I have List of Maps as

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

And I want a Map as

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

答案1

得分: 7

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

  1. var listOfMaps = List.of(
  2. Map.of("a", 10, "b", 20),
  3. Map.of("a", 12, "b", 22),
  4. Map.of("a", 14, "b", 24)
  5. );
  6. var mapOfLists = listOfMaps.stream()
  7. .map(Map::entrySet)
  8. .flatMap(Set::stream)
  9. .collect(Collectors.groupingBy(
  10. Map.Entry::getKey,
  11. Collectors.mapping(
  12. Map.Entry::getValue,
  13. Collectors.toList()
  14. )
  15. ));
  16. 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.

  1. var listOfMaps = List.of(
  2. Map.of("a", 10, "b", 20),
  3. Map.of("a", 12, "b", 22),
  4. Map.of("a", 14, "b", 24)
  5. );
  6. var mapOfLists = listOfMaps.stream()
  7. .map(Map::entrySet)
  8. .flatMap(Set::stream)
  9. .collect(Collectors.groupingBy(
  10. Map.Entry::getKey,
  11. Collectors.mapping(
  12. Map.Entry::getValue,
  13. Collectors.toList()
  14. )
  15. ));
  16. 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部分,您告诉它将被分组的值以及如何收集它们(在我们的情况下,我们希望它们成为一个列表)。

  1. Map<String, String> ma = new java.util.HashMap<>();
  2. ma.put("a", "10");
  3. ma.put("b", "20");
  4. Map<String, String> ma3 = new java.util.HashMap<>();
  5. ma3.put("a", "15");
  6. ma3.put("b", "17");
  7. ma3.put("c", "19");
  8. List<Map<String, String>> list = Arrays.asList(ma, ma3);
  9. Map<String, List<String>> lm = list.stream()
  10. .flatMap(x -> x.entrySet().stream())
  11. .collect(Collectors.groupingBy(
  12. Entry::getKey,
  13. HashMap::new,
  14. Collectors.mapping(Entry::getValue, Collectors.toList())
  15. ));
  16. System.out.println(lm);

输出看起来像这样:

  1. {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)

  1. Map&lt;String, String&gt; ma = new java.util.HashMap&lt;&gt;();
  2. ma.put(&quot;a&quot;, &quot;10&quot;);
  3. ma.put(&quot;b&quot;, &quot;20&quot;);
  4. Map&lt;String, String&gt; ma3 = new java.util.HashMap&lt;&gt;();
  5. ma3.put(&quot;a&quot;, &quot;15&quot;);
  6. ma3.put(&quot;b&quot;, &quot;17&quot;);
  7. ma3.put(&quot;c&quot;, &quot;19&quot;);
  8. List&lt;Map&lt;String, String&gt;&gt; list = Arrays.asList(ma, ma3);
  9. Map&lt;String, List&lt;String&gt;&gt; lm = list.stream().flatMap(x -&gt; x.entrySet().stream()).collect(Collectors
  10. .groupingBy(Entry::getKey, HashMap::new, Collectors.mapping(Entry::getValue, Collectors.toList())));
  11. System.out.println(lm);

Output looks like

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

答案3

得分: 3

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

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

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

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

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

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

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 中使用重新映射功能。

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

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

  1. final Map&lt;String,List&lt;String&gt;&gt; result = new HashMap&lt;&gt;();
  2. maps.forEach(map -&gt; map.entrySet().forEach(entry -&gt;
  3. result.merge(entry.getKey(), Arrays.asList(entry.getValue()),
  4. (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:

确定