通过与另一个Set中的键匹配,在Map中添加BigDecimals

时间:2018-05-28 01:18:33

标签: java lambda collectors

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

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. 将新地图的valueSet转换为流
  5. 将值缩减为单个BigDecimal
  6. 有没有办法减少步数?这样做会提高效率吗?或者这是最好的解决方案吗?

2 个答案:

答案 0 :(得分:3)

你可以稍微缩短它:

BigDecimal sum = years.stream()
    .map(y -> sales_by_year.getOrDefault(y, BigDecimal.ZERO))  
    .reduce(BigDecimal.ZERO, BigDecimal::add);

答案 1 :(得分:1)

以下效率更高,因为:

  • 没有中间收藏
  • 迭代较小的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);