将多个 BigDecimals 求和到一个 Map<String, BigDecimal>

Sum multiple BigDecimals to a Map<String, BigDecimal>

我正在尝试对 List 中的多个 BigDecimals 求和。目前,我正在使用两个流,但如果可能的话,我希望只有一个流。我不确定如何以高效的方式重写下面的内容。

BigDecimal totalCharges = tableRowDataList.stream()
            .map(el -> el.getSums().getCharges())
            .reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal totalFees = tableRowDataList.stream()
            .map(el -> el.getSums().getFees())
            .reduce(BigDecimal.ZERO, BigDecimal::add);

如您所见,流的作用基本相同,只是对 getCharges/getFees 的调用不同。

从上面获得结果 Map<String, BigDecimal> 的最佳方法是什么? (关键是 charges/fees)

首先创建一个 class 用于收集结果。

然后你做与 BigDecimal 相同的事情,即一个 ZERO 常量和一个 add() 方法。

public class ChargesAndFees {
    private static final ZERO = new ChargesAndFees(BigDecimal.ZERO, BigDecimal.ZERO);

    private final BigDecimal charges;
    private final BigDecimal fees;

    // constructor and getters

    public ChargesAndFees add(ChargesAndFees that) {
        return new ChargesAndFees(this.charges.add(that.charges),
                                  this.fees.add(that.fees));
    }
}

现在你可以做流逻辑了

ChargesAndFees totals = tableRowDataList.stream()
        .map(el -> new ChargesAndFees(el.getSums().getCharges(),
                                      el.getSums().getFees()))
        .reduce(ChargesAndFees.ZERO, ChargesAndFees::add);

如果你坚持,你可以将 totals 中的值转换为 Map

如果您有一个对象列表 List,其中每个对象都有一个 Sums 对象——您是否控制 TableRowDataElement and/or Sums 的定义?

如果您在 TableRowDataElement 或 Sums 中创建一个 add 方法,那么您可以简化它而无需额外的 class--

Sums sums = tableRowDataList.stream()
        .map(el -> el.getSums())
        .reduce(new Sums(0,0), Sums::add);

尝试 StreamEx:

Optional<Entry<BigDecimal, BigDecimal>> res = StreamEx.of(tableRowDataList)
            .map(e -> e.getSums())
            .mapToEntry(s -> s.getCharges(), s -> s.getFees())
            .reduce((a, b) -> {
                a.getKey().add(b.getKey());
                b.getKey().add(b.getValue());
                return a;
            });

我认为我们应该尽量避免创建那些小助手类。否则,您将 运行 陷入维护 tens/hundreds 微小 类 的麻烦中。