如何将列表中的地图展平?

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

How to flatten a map inside a list?

问题

import java.util.*;
import java.util.stream.Collectors;

List<Map<String, Object>> source = List.of(
    Map.of("type", "first_type", "value", "1"),
    Map.of("type", "first_type", "value", "2"),
    Map.of("type", "second_type", "value", "3")
);

Map<String, List<Object>> goal = source.stream()
    .collect(Collectors.groupingBy(
        e -> (String) e.get("type"),
        Collectors.mapping(e -> e.get("value"), Collectors.toList())
    ));
英文:

I have a list of maps, each map showing the same key attributes type and value.

Question: how can I use java streams to flatten this into a Map&lt;String, List&gt;&gt;?

List&lt;Map&lt;String, Object&gt;&gt; source = List.of(
	Map.of(&quot;type&quot;, &quot;first_type&quot;, &quot;value&quot;, &quot;1&quot;),
	Map.of(&quot;type&quot;, &quot;first_type&quot;, &quot;value&quot;, &quot;2&quot;),
	Map.of(&quot;type&quot;, &quot;second_type&quot;, &quot;value&quot;, &quot;3&quot;)
);

Goal:
Map&lt;String, List&lt;Object&gt;&gt; goal = Map.of(
	&quot;first_type&quot;, List.of(&quot;1&quot;, &quot;2&quot;),
	&quot;second_type&quot;, List.of(&quot;3&quot;)
);

It's probably similar to the following, but how can I group the nested map values by their type?

 source.stream()
            .collect(Collectors.toMap(e -&gt; e.getKey(), e -&gt; e.getValue()));

答案1

得分: 4

我们可以使用Collectors.groupingBy来实现这一点。

Map<String, List<Object>> goal = source.stream()
        .collect(Collectors.groupingBy(e -> (String) e.get("type"),
                Collectors.mapping(e -> e.get("value"), Collectors.toList())));

由于结果映射的键是字符串,因此在提取键(type)时需要进行丑陋的类型转换。

英文:

We can achieve this using Collectors.groupingBy.

Map&lt;String, List&lt;Object&gt;&gt; goal = source.stream()
        .collect(Collectors.groupingBy(e -&gt; (String) e.get(&quot;type&quot;),
                Collectors.mapping(e -&gt; e.get(&quot;value&quot;), Collectors.toList())));

Since the key of the result map is a String, there is an ugly type-casting when extracting the key (type).

答案2

得分: 2

你可以使用 Collectors.groupingBytype 进行分组,然后使用 Collectors.mapping 映射 value 并收集为列表:

Map<Object, List<Object>> goal = 
  source.stream()
        .collect(Collectors.groupingBy(m -> m.get("type"),
                  Collectors.mapping(m -> m.get("value"), Collectors.toList())));

最好将结果保存在 Map<Object, List<Object>> 中,以使映射的键为 Object,避免进行类型转换。

英文:

You can use Collectors.groupingBy to grouping by type and Collectors.mapping to map the value and collect as List

Map&lt;Object, List&lt;Object&gt;&gt; goal = 
  source.stream()
        .collect(Collectors.groupingBy(m -&gt; m.get(&quot;type&quot;),
                  Collectors.mapping(m -&gt; m.get(&quot;value&quot;), Collectors.toList())));

It's better get result in Map&lt;Object, List&lt;Object&gt;&gt; as map key is Object to avoid type casting.

答案3

得分: 0

只需将地图流式传输并提取类型和值,然后将它们映射到列表中。
这使用groupingBy将值分组到目标供应商中。但是您需要先映射该值,然后将供应商指定为List。我还将Object更改为String,因为那是您正在使用的内容。

Map<String, List<String>> map =
    source.stream()
        .collect(Collectors.groupingBy(m -> m.get("type"),
            Collectors.mapping(m -> m.get("value"),
                Collectors.toList())));

map.entrySet().forEach(System.out::println);

打印结果为

first_type=[1, 2]
second_type=[3]

当然,您也可以这样做。这将被翻译为:

  • 如果指定的键type对应的ArrayList存在,请使用它。
  • 否则创建它。
  • 在任一情况下,它都会从compute方法返回该列表,其中添加了value键的值。
Map<String, List<String>> map = new HashMap<>();
for (Map<String, String> m : source) {
    map.compute(m.get("type"), (k, v) -> v == null ?
            new ArrayList<>() : v).add(m.get("value"));
}
英文:

Just Stream the maps and pull off the type and values. Then map them to a list.
This uses groupingBy to group the values into a target supplier. But you need to map the value first and then specify the supplier as a List. I also changed Object to String since that is what you are using.

Map&lt;String, List&lt;String&gt;&gt; map =
		source.stream()
				.collect(Collectors.groupingBy(m-&gt;m.get(&quot;type&quot;),
						Collectors.mapping(m-&gt;m.get(&quot;value&quot;),
								Collectors.toList())));

map.entrySet().forEach(System.out::println);

Prints

first_type=[1, 2]
second_type=[3]

Of course, you could also do it like this. This translates to:

  • if the ArrayList is there for the specified key type, use it.
  • otherwise create it.
  • In either case it returns that list from the compute method where<br>
    the value for the value key is added.
Map&lt;String,List&lt;String&gt;&gt; map = new HashMap&lt;&gt;();
for(Map&lt;String,String&gt; m : source) {
	map.compute(m.get(&quot;type&quot;), (k,v)-&gt; v == null ?
            new ArrayList&lt;&gt;(): v).add(m.get(&quot;value&quot;));
}

</details>



huangapple
  • 本文由 发表于 2020年10月7日 22:54:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/64246719.html
匿名

发表评论

匿名网友

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

确定