我有一张地图清单如下。
我想按键对条目集进行分组, 如果一个密钥不存在,请填写0。
List<Map<String, Double>> props = Lists.newArrayList();
Map<String, Double> m1 = Maps.newHashMap();
m1.put("a", 0.1);
m1.put("b", 0.5);
m1.put("c", 0.6);
Map<String, Double> m2 = Maps.newHashMap();
m2.put("a", 0.3);
m2.put("d", 0.1);
Map<String, Double> m3 = Maps.newHashMap();
m3.put("a", 0.2);
props.add(m1); props.add(m2); props.add(m3);
预期结果:
{a=[0.1, 0.3, 0.2], b=[0.5, 0, 0], c=[0.6,0,0], d=[0,0.1,0]}
我有个主意:
有什么好主意吗?
答案 0 :(得分:3)
可以在单行lamda和流中完成,除了填充每个丢失键的地图值为0
Map<String, List<Double>> collect = Stream.of(m1, m2, m3)
.flatMap(map -> map.entrySet().stream())
.collect(groupingBy(
Map.Entry::getKey,
mapping(Map.Entry::getValue, toList()))
);
System.out.println(collect);
这将产生输出
{a=[0.1, 0.3, 0.2], b=[0.5], c=[0.6], d=[0.1]}
此处静态工厂方法Collectors.groupingBy()
用于按键(classifier
)和映射方法(collector
)对所有映射的连接条目进行分组。
如果是明显的情况,你必须用值0 填充每个缺失键的地图,那么有几种方法可以做到这一点。一个@abhi在其他答案中说。除了他的想法,我想这样做
Set<String> allKeys = Sets.newHashSet();
props.forEach(prop -> allKeys.addAll(prop.keySet()));
allKeys.forEach(k -> props.forEach(m -> m.putIfAbsent(k, 0.0)));
事实上,这会修改原始地图,allKeys
0
为ifNotPresent
。如果此修改导致您出现问题,您可以更喜欢将地图复制为具有单独的集合。
这将确保您所需的输出
{a=[0.1, 0.3, 0.2], b=[0.5, 0.0, 0.0], c=[0.6, 0.0, 0.0], d=[0.0, 0.1, 0.0]}
注意:您可以找到有关Grouping using Java 8 streams
的文章答案 1 :(得分:1)
代码效率不高,但它完成了工作。
List<Map<String, Double>> props = new ArrayList<>();
Map<String, Double> m1 = new HashMap<>();
m1.put("a", 0.1);
m1.put("b", 0.5);
m1.put("c", 0.6);
Map<String, Double> m2 = new HashMap<>();
m2.put("a", 0.3);
m2.put("d", 0.1);
Map<String, Double> m3 = new HashMap<>();
m3.put("a", 0.2);
props.add(m1);
props.add(m2);
props.add(m3);
Set<String> allKeys = new HashSet<>();
for (Map<String, Double> prop : props) {
allKeys.addAll(prop.keySet());
}
HashMap<String, ArrayList<Double>> result = new HashMap<>();
for (Map<String, Double> prop : props) {
for (String key : allKeys) {
if(!result.containsKey(key)){
result.put(key, new ArrayList<>());
}
if(!prop.containsKey(key)){
prop.put(key, 0.0);
}
Double propValue = prop.get(key);
result.get(key).add(propValue);
}
}
System.out.println(result.toString());
你基本上想要使用Set<String>
然后遍历所有地图来获取他们的keys
,然后当你拥有所有密钥需要迭代所有地图时,检查密钥是否存在,如果没有,则将其添加到地图,现在您可以将其添加到HashMap<String, ArrayList<Double>>
,因为您知道此地图的密钥存在
答案 2 :(得分:1)
java 8肯定会减少行数,但不会减少你的情况下的一行代码
Set<String> keys = Sets.newHashSet();
props.forEach(prop -> keys.addAll(prop.keySet()));
Map<String, List<Double>> result = Maps.newHashMap();
keys.forEach(key -> result.put(key, new ArrayList<>(Collections.nCopies(props.size(), 0D))));
props.forEach(prop -> prop.forEach((key, value) -> result.get(key).set(props.indexOf(prop), value)));
System.out.println(result);