java - 使用流将多个 HashMap 的内容相加

标签 java java-8 bigdecimal java-stream

我有一个 HashMap 矩阵,我试图根据给定的输入将这些 HashMap 的内容相加,这将匹配“外部”HashMap 的键。拿下面的SSCCE(有1个错误说明我的进度),HashMaps有4行HashMap,我想把第1行和第3行的HashMaps的内容加起来。

当然,我可以用旧的 Java 7 方式来做这件事。但我想使用 Java 8 流来执行此操作而无需迭代。

public class HashMapCollector {
    public static void main(String[] args) {
        HashMap<Integer, HashMap<Integer, BigDecimal>> map = new HashMap<>();
        map.put(1, new LinkedHashMap<>()); // row 1
        map.put(2, new LinkedHashMap<>()); // row 2
        map.put(3, new LinkedHashMap<>()); // row 3
        map.put(4, new LinkedHashMap<>()); // row 4

        // row 1
        map.get(1).merge(1, BigDecimal.TEN, BigDecimal::add);
        map.get(1).merge(2, BigDecimal.TEN, BigDecimal::add);
        map.get(1).merge(3, BigDecimal.TEN, BigDecimal::add);
        map.get(1).merge(4, BigDecimal.TEN, BigDecimal::add);

        // row 2
        map.get(2).merge(1, BigDecimal.TEN, BigDecimal::add);
        map.get(2).merge(2, BigDecimal.TEN, BigDecimal::add);
        map.get(2).merge(3, BigDecimal.TEN, BigDecimal::add);
        map.get(2).merge(4, BigDecimal.TEN, BigDecimal::add);

        // row 3
        map.get(3).merge(1, BigDecimal.TEN, BigDecimal::add);
        map.get(3).merge(2, BigDecimal.TEN, BigDecimal::add);
        map.get(3).merge(3, BigDecimal.TEN, BigDecimal::add);
        map.get(3).merge(4, BigDecimal.TEN, BigDecimal::add);

        // row 4
        map.get(4).merge(1, BigDecimal.TEN, BigDecimal::add);
        map.get(4).merge(2, BigDecimal.TEN, BigDecimal::add);
        map.get(4).merge(3, BigDecimal.TEN, BigDecimal::add);
        map.get(4).merge(4, BigDecimal.TEN, BigDecimal::add);

        // Using a HashSet to contain the keys of the rows I want
        HashSet<Integer> keys_to_add = new HashSet<>();
        keys_to_add.add(1);
        keys_to_add.add(3);

        // Java 7 boring vanilla iteration
        BigDecimal total = BigDecimal.ZERO;
        for(Entry<Integer, HashMap<Integer, BigDecimal>> entry : map.entrySet()) {
            if(keys_to_add.contains(entry.getKey())) {
                for(BigDecimal bd : entry.getValue().values()) {
                    total = total.add(bd);
                }
            }
        }

        System.out.println(total);

        // Java 8ish method -- still some boring iteration
        total = BigDecimal.ZERO;
        for(Entry<Integer, HashMap<Integer, BigDecimal>> entry : map.entrySet()) {
            if(keys_to_add.contains(entry.getKey())) {
                total = total.add(entry.getValue().values().stream().reduce(BigDecimal.ZERO, BigDecimal::add));
            }
        }

        System.out.println(total);


        // Java 8 method -- no iteration
        total = BigDecimal.ZERO;
        map.entrySet().stream().filter(e -> keys_to_add.contains(e.getKey())).map(Map.Entry::getValue). // This is as far as I got

        System.out.println(total);
    }
}

最佳答案

我认为从 keys_to_add 开始比遍历所有条目并检查 key 是否在 keys_to_add 中更有意义。

BigDecimal total = keys_to_add.stream()
        .filter(map::containsKey)
        .map(map::get)
        .map(Map::values)
        .flatMap(Collection::stream)
        .reduce(BigDecimal::add)
        .orElse(BigDecimal.ZERO);

或者,如果您更喜欢节省垂直空间,

BigDecimal total = keys_to_add.stream()
        .filter(map::containsKey)
        .flatMap(k -> map.get(k).values().stream())
        .reduce(BigDecimal.ZERO, BigDecimal::add);

关于java - 使用流将多个 HashMap 的内容相加,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29786516/

相关文章:

Java jar在ubuntu上创建多个进程但在mac上不创建

java - 如何使用带有加密功能的 SQLiteJDBC 库 (sqlite-jdbc-crypt)

java - 如何将 java.util.Optional 与 REST API 一起使用?

java - 服务器端mp3编码

javascript - 如何使用 javaScript 获取从 java 类传递到 native 脚本 jar 文件的变量数据

java - 将按钮添加到选项卡和选项卡区域 JavaFX

java - 在夏令时前后将 Duration.ofDays(1) 和 Period.ofDays(1) 添加到 ZonedDateTime 之间的区别

java - BeanUtils.setProperty 方法将 BigDecimal 字段设置为 null

ruby - 某些 BigDecimal 无法使用 ** 运算符计算

java - 格式化 BigDecimal 或不带小数分隔符的数字