[英]Convert a list of maps to a map of lists using Java Streams
我想将地图列表转换为列表地图。 保证所有映射都具有相同的键。
例如,下面的列表
[{key1: val1, key2: val2}, {key1: val3, key2: val4}]
转换为
{key1: [val1, val3], key2: [val2, val4]}
下面的代码使用 for 循环
List<Map<String, Object>> data = getData();
Map<String, List<Object>> result = new HashMap<>();
for (Map<String, Object> element: data) {
element.forEach((key, val) -> {
if (result.containsKey(key))
result.get(key).add(val);
else
result.put(key, Arrays.asList(val));
});
}
我如何才能使用流实现相同的结果?
例如像这样,依靠java流的收集阶段。
List<Map<String, Object>> data = new ArrayList<>();
HashMap<String, List<Object>> transposed = data.stream()
.flatMap(i -> i.entrySet().stream())
.collect(Collectors.groupingBy(
Map.Entry::getKey,
HashMap::new,
Collectors.mapping(Map.Entry::getValue,
Collectors.toCollection(ArrayList::new))));
在 SO 上有许多这样的应用程序(例如这个),尽管不是针对这个例子精确定制的。
这个依赖stream.reduce
版本应该这样做:
// some values for testing
List<Map<String, Object>> list = new ArrayList<>();
list.add(Map.of("1", "One", "2", "Two"));
list.add(Map.of("3", "Three", "4", "Four", "5", "Five"));
list.add(Map.of("3", "Teen", "5", "Penta"));
list.add(Map.of("3", "Trice", "4", "Quattro"));
// conversion with stream reduction
Map<String, List<Object>> result = list.stream().reduce(new HashMap<>(),
(acc, map) -> {
map.forEach((k, v) -> acc.computeIfAbsent(k,
l -> new ArrayList<Object>()).add(v));
return acc;
},
(acc1, acc2) -> {
acc1.putAll(acc2);
return acc1;
});
// output
System.out.println(result);
//{1=[One], 2=[Two], 3=[Three, Teen, Trice], 4=[Four, Quattro], 5=[Five, Penta]}
说明:此代码遍历列表中的每个映射并将其累积在哈希映射中(reduce 函数的第一个参数),如果第一次看到键,则累积函数(第二个参数)向哈希映射添加一个新列表(否则它会累积在已经存在的列表中); 第三个函数是串行或并行运行流函数之间的一致性所必需的(它在并行运行中合并部分结果)。
您可以在没有流的情况下以现代方式执行此操作,如下所示:
Map<String, List<Object>> result = new HashMap<>();
data.forEach(element ->
element.forEach((k, v) - >
result.computeIfAbsent(k, x -> new ArrayList<>()).add(v)));
这将迭代列表,然后迭代每个映射,并使用Map.computeIfAbsent
来容纳result
映射中的条目。
您可以使用Collectors.toMap
方法:
List<Map<String, String>> listOfMaps = List.of(
Map.of("key1", "val1", "key2", "val2"),
Map.of("key1", "val3", "key2", "val4"));
Map<String, List<String>> mapOfLists = listOfMaps.stream()
// Stream<Map<String,String>>
.flatMap(map -> map.entrySet().stream())
// Stream<Map.Entry<String,String>>
.collect(Collectors.toMap(
// key
Map.Entry::getKey,
// value
e -> List.of(e.getValue()),
// merge function
(list1, list2) -> {
List<String> list = new ArrayList<>();
list.addAll(list1);
list.addAll(list2);
return list;
}, // map factory
LinkedHashMap::new));
System.out.println(listOfMaps);
// [{key1=val1, key2=val2}, {key1=val3, key2=val4}]
System.out.println(mapOfLists);
// {key1=[val1, val3], key2=[val2, val4]}
另请参阅:将列表映射转换为映射列表
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.