简体   繁体   English

java8按键减少的地图列表

[英]java8 a list of map reduce by key

I have a list of maps as below. 我有一份地图清单如下。

And I want to group the entry sets by key, if a key non exist, fill 0 instead. 并且我想按密钥对条目集进行分组,如果密钥不存在,则填充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);

Expected result: 预期结果:

{a=[0.1, 0.3, 0.2], b=[0.5, 0, 0], c=[0.6,0,0], d=[0,0.1,0]}

I got an idea: 我有个主意:

  1. find all distinct keys 找到所有不同的键
  2. fill every map of missing keys with value 0 用值0填充缺失键的每个映射
  3. groupby key, values mapping to a list groupby键,值映射到列表

Any good ideas? 有什么好主意吗?

It can be done in single line lamda and stream except the case fill every map of missing keys with value 0 它可以在单行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);

And this will produce the output as 这将产生输出

{a=[0.1, 0.3, 0.2], b=[0.5], c=[0.6], d=[0.1]}

Here static factory methods Collectors.groupingBy() is used to group the concatenated Entries of all maps by the Key ( classifier ) and mapping method ( collector ). 这里静态工厂方法Collectors.groupingBy()用于通过Key( classifier )和映射方法( collector )对所有映射的连接条目进行分组。

If its the obvious case you must to fill every map of missing keys with value 0 then there is several way of doing that. 如果是明显的情况,你必须用值0填充缺失键的每个映射,那么有几种方法可以做到这一点。 One that @abhi stated in other answer. 一个@abhi在其他答案中说。 Along with his idea I would like to do that this way 除了他的想法,我想这样做

  Set<String> allKeys = Sets.newHashSet();
  props.forEach(prop -> allKeys.addAll(prop.keySet()));
  allKeys.forEach(k -> props.forEach(m -> m.putIfAbsent(k, 0.0)));

Infact this will modify your original maps with allKeys having 0 as value ifNotPresent . 事实上,这将修改原始地图,其中allKeys值为0 ifNotPresent If this modification causes you problem you can prefer to copy your maps to have separate collections. 如果此修改导致您出现问题,您可以更喜欢将地图复制为具有单独的集合。

This will ensure your desired output 这将确保您所需的输出

{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]}

Note: You can find this article interesting about Grouping using Java 8 streams 注意:您可以在本文中找到有关使用Java 8流进行分组的有趣内容

The code is not very efficient, but it gets the job done. 代码效率不高,但它完成了工作。

    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());

You basically want to use a Set<String> then iterate through all the maps to get their keys , then when you have all the keys you need to iterate through all the maps, check if the key exists, if it doesn't then add it to the map and now you can add it to the HashMap<String, ArrayList<Double>> because you know that the key exists for this map 您基本上想要使用Set<String>然后遍历所有映射以获取其keys ,然后当您拥有所有密钥需要迭代所有映射时,检查密钥是否存在,如果不存在则添加它到地图,现在你可以将它添加到HashMap<String, ArrayList<Double>>因为你知道这个地图的密钥存在

java 8 surely does reduce the number of lines, but not to one line of code in your case 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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM