java8按键减少的地图列表

时间:2017-12-10 04:35:40

标签: java java-8

我有一张地图清单如下。

我想按键对条目集进行分组, 如果一个密钥不存在,请填写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]}

我有个主意:

  1. 找到所有不同的密钥
  2. 用值0
  3. 填充缺失键的每个地图
  4. groupby键,值映射到列表
  5. 有什么好主意吗?

3 个答案:

答案 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 0ifNotPresent。如果此修改导致您出现问题,您可以更喜欢将地图复制为具有单独的集合。

这将确保您所需的输出

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