我正在尝试将Stream<Map<String, Map<String, String>>>
对象合并到一个具有所有Streams
中键的单个映射中。
例如,
final Map<String, someOtherObjectToProcess> someObject;
final List<Map<String, Map<String, String>>> list = someObject.entrySet()
.stream()
.flatMap(this::getInfoStream)
.collect(Collectors.toList());
getInfoStream的签名是
public Stream<Map<String, Map<String, String>>> getInfoStream(Map.Entry<String, someOtherObjectToProcess> entry)
如果我使用(Collectors.toList())
,则可以获取这些Map对象的列表。
如果使用上述代码,则输出示例:
[{
"name" : {
"property":"value"
}
},
{
"name2" : {
"property":"value"
}
}]
但是我想用结构收集到地图中
{
"name" : {
"property":"value"
},
"name2" : {
"property":"value"
}
}
提供了唯一的键。
我该如何使用Collectors.toMap()或其他任何替代方法?
答案 0 :(得分:3)
有空
Stream<Map<String, Map<String, String>>> stream = ...
(我假设是.flatMap(this::getInfoStream)
的结果),您可以致电
.flatMap(map -> map.entrySet().stream())
从所有地图创建条目流,这些条目将产生Stream<Map.Entry<String, Map<String, String>>>
。
现在从该流中,您要做的就是从地图的每个条目中 collect 键和值。假设每个键在您可以使用的所有地图上都是唯一的
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
但是,如果键不是唯一的,则需要确定应在同一键的新映射中放置什么值。我们可以通过填充...
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (vOld, vNew) -> ...));
// ^^^
其中vOld
保留当前在相同键下的结果映射中保留的值,而vNew
保留新值(来自当前流“ iteration”)。
例如,如果您想忽略新值,则可以简单地返回{/ {1}}
简而言之(假设唯一键):
(vOld, vNew) -> vOld
答案 1 :(得分:1)
解决此问题的另一种方法不是使用collector(toList())
,而是使用供应商,累加器和合并器的另一种重载.collect()
方法:
Stream<Map<String, Map<String, String>>> stream = ...
Map<String, Map<String, String>> result = stream
.collect(HashMap::new, HashMap::putAll, HashMap::putAll);
答案 2 :(得分:1)
我认为最易读的方式是将所有内容映射到app.use(...)
,然后使用Map.Entry
将所有内容收集回Map
Collectors::toMap
import static java.util.stream.Collectors.toMap;
// ...
someObject.entrySet()
.stream()
.flatMap(this::getInfoStream)
.flatMap(map -> map.entrySet().stream())
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (one, two) -> one));
是合并功能,基本上,如果您有重复项,则可以任意选择第一个出现的
答案 3 :(得分:1)
TL; DR:
var merged = Stream.of(map1, map2, ..., mapN).reduce(new HashMap<>(), (a, b) -> {
a.putAll(b);
return a;
});
您可以使用reduce
将Map<String, Map<String, String>>
元素流合并为一个:
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
alternative1();
alternative2();
}
// Use reduce without an initial identity value
public static void alternative1() {
Map<String, Map<String, String>> m1 = new HashMap<>();
m1.put("name", Map.of("property", "value"));
Map<String, Map<String, String>> m2 = new HashMap<>();
m2.put("name2", Map.of("property", "value"));
Stream<Map<String, Map<String, String>>> mapStream = Stream.of(m1, m2);
Map<String, Map<String, String>> m3 = mapStream.reduce((a, b) -> {
Map<String, Map<String, String>> temp = new HashMap<>();
temp.putAll(a);
temp.putAll(b);
return temp;
}).orElseThrow();
System.out.println(m3);
}
// Use reduce with an initial empty map as the identity value
public static void alternative2() {
Map<String, Map<String, String>> m1 = new HashMap<>();
m1.put("name", Map.of("property", "value"));
Map<String, Map<String, String>> m2 = new HashMap<>();
m2.put("name2", Map.of("property", "value"));
Stream<Map<String, Map<String, String>>> mapStream = Stream.of(m1, m2);
Map<String, Map<String, String>> m3 = mapStream.reduce(new HashMap<>(), (a, b) -> {
a.putAll(b);
return a;
});
System.out.println(m3);
}
}
输出:
{name={property=value}, name2={property=value}}
{name={property=value}, name2={property=value}}
但是请注意,这些解决方案假定键(name
和name2
)是唯一的,否则重复的键会使映射条目相互覆盖。
具有更现代语法的相同逻辑:
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
alternative1();
alternative2();
}
// Use reduce without an initial identity value
public static void alternative1() {
var m1 = Map.of("name", Map.of("property", "value"));
var m2 = Map.of("name2", Map.of("property", "value"));
var m3 = Stream.of(m1, m2).reduce((a, b) -> {
var temp = new HashMap<String, Map<String, String>>();
temp.putAll(a);
temp.putAll(b);
return temp;
}).orElseThrow();
System.out.println(m3);
}
// Use reduce with an initial empty map as the identity value
public static void alternative2() {
var m1 = Map.of("name", Map.of("property", "value"));
var m2 = Map.of("name2", Map.of("property", "value"));
var m3 = Stream.of(m1, m2).reduce(new HashMap<>(), (a, b) -> {
a.putAll(b);
return a;
});
System.out.println(m3);
}
}