gpt4 book ai didi

java - 使用 Java 8 流运算符将两级映射列表减少为单个两级映射

转载 作者:搜寻专家 更新时间:2023-10-31 20:00:56 26 4
gpt4 key购买 nike

我有一个嵌套 map 列表 ( List<Map<String, Map<String, Long>>> ),目标是将列表缩减为单个 map ,合并按如下方式进行:如果 map1包含 x->{y->10, z->20}map2包含 x->{y->20, z->20}那么这两个应该合并到x->{y->30, z->40} .

我尝试按照以下方式进行操作,效果很好。

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.BinaryOperator;
import java.util.stream.Collectors;

public class Test {
public static void main(String args[]) throws IOException {
Map<String, Map<String, Long>> data1 = new HashMap<>();
Map<String, Long> innerData1 = new HashMap<>();
innerData1.put("a", 10L);
innerData1.put("b", 20L);
data1.put("x", innerData1);
Map<String, Long> innerData2 = new HashMap<>();
innerData2.put("b", 20L);
innerData2.put("a", 10L);
data1.put("x", innerData1);

Map<String, Map<String, Long>> data2 = new HashMap<>();
data2.put("x", innerData2);

List<Map<String, Map<String, Long>>> mapLists = new ArrayList<>();
mapLists.add(data1);
mapLists.add(data2);

Map<String, Map<String, Long>> result = mapLists.stream().flatMap(map -> map.entrySet().stream()).
collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, new BinaryOperator<Map<String, Long>>() {

@Override
public Map<String, Long> apply(Map<String, Long> t,
Map<String, Long> u) {
Map<String, Long> result = t;
for(Entry<String, Long> entry: u.entrySet()) {
Long val = t.getOrDefault(entry.getKey(), 0L);
result.put(entry.getKey(), val + entry.getValue());
}
return result;
}
}));
}
}

有没有其他更好更有效的方法来解决这个问题?

如果嵌套层数大于2,如何做的更干净?假设列表类似于 List<Map<String, Map<String, Map<String, Long>>>>我们必须将它减少到一个 Map<String, Map<String, Map<String, Long>>> ,假设与上述类似的合并功能。

最佳答案

你有大概的想法,把两张 map 合并在一起的过程稍微简化一下就可以了。 Merging the two maps can be done easily with :

Map<String, Integer> mx = new HashMap<>(m1);
m2.forEach((k, v) -> mx.merge(k, v, Long::sum));

此代码创建合并 map mx来自 m1 ,然后遍历第二个映射的所有条目 m2并将每个条目合并到 mx Map.merge(key, value, remappingFunction) 的帮助下:如果该键不存在映射,此方法将添加给定键和给定值,否则它将使用给定的重新映射函数重新映射该键的现有值和给定值。在我们的例子中,重映射函数应该将两个值相加。

代码:

Map<String, Map<String, Long>> result  =
mapLists.stream()
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(m1, m2) -> {
Map<String, Long> mx = new HashMap<>(m1);
m2.forEach((k, v) -> mx.merge(k, v, Long::sum));
return mx;
}
));

如果有更多的“级别”,你可以定义一个merge方法:

private static <K, V> Map<K, V> merge(Map<K, V> m1, Map<K, V> m2, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
Map<K, V> mx = new HashMap<>(m1);
m2.forEach((k, v) -> mx.merge(k, v, remappingFunction));
return mx;
}

并递归使用它。例如合并两个Map<String, Map<String, Long>> m1m2 ,你可以使用

merge(m1, m2, (a, b) -> merge(a, b, Long::sum));

因为重映射函数是Collectors.toMap .

关于java - 使用 Java 8 流运算符将两级映射列表减少为单个两级映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34598910/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com