代码之家  ›  专栏  ›  技术社区  ›  ryvantage

通过与另一组中的键匹配,在地图中添加大小数

  •  0
  • ryvantage  · 技术社区  · 7 年前

    我有一张销售数字除以年份的地图:

    Map<Integer, BigDecimal> sales_by_year = new TreeMap<>();
    sales_by_year.put(2012, BigDecimal.valueOf(19283));
    sales_by_year.put(2013, BigDecimal.valueOf(24832));
    sales_by_year.put(2014, BigDecimal.valueOf(19562));
    sales_by_year.put(2015, BigDecimal.valueOf(21879));
    sales_by_year.put(2016, BigDecimal.valueOf(23587));
    sales_by_year.put(2017, BigDecimal.valueOf(28756));
    

    我想把这些年的销售额加起来:

    Set<Integer> years = new HashSet<>(Arrays.asList(new Integer[] {2012, 2013, 2014}));
    

    我想写一个lambda把这些年合并成一个 BigDecimal . 我写的:

    BigDecimal sales_for_timeframe = sales_by_year.entrySet().stream()
            .filter(a -> years.contains(a.getKey()))
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))
            .values().stream()
            .reduce(BigDecimal.ZERO, BigDecimal::add);
    
    System.out.println(sales_for_timeframe);
    

    而且它是有效的。但这是最有效的方法吗?此解决方案:

    1. 将地图转换为流
    2. 过滤地图
    3. 将其重新收集到新地图中
    4. 将新映射的值集转换为流
    5. 将值减少到单个 大十进制

    有没有办法减少步骤的数量?这样做会提高效率吗?或者这是最好的解决方案?

    2 回复  |  直到 7 年前
        1
  •  3
  •   jspcal    7 年前

    你可以稍微缩短一点:

    BigDecimal sum = years.stream()
        .map(y -> sales_by_year.getOrDefault(y, BigDecimal.ZERO))  
        .reduce(BigDecimal.ZERO, BigDecimal::add);
    
        2
  •  1
  •   Andreas dfa    7 年前

    以下内容将更有效,因为:

    • 无中间收款
    • 迭代较小的 years 设置,而不是更大的 sales_by_year 地图
    BigDecimal sales_for_timeframe = years.stream()
            .map(yr -> sales_by_year.getOrDefault(yr, BigDecimal.ZERO))
            .filter(bd -> bd.signum() != 0) // prevent unnecessary adds (optional)
            .reduce(BigDecimal.ZERO, BigDecimal::add);
    

    在之前的编辑中, answer by jspcal 有了这个替代实现,完全使用方法引用:

    BigDecimal sales_for_timeframe = years.stream()
            .map(sales_by_year::get)
            .filter(Objects::nonNull)
            .reduce(BigDecimal.ZERO, BigDecimal::add);