Java 8流 - 合并共享相同Id的对象集合

jau*_*udo 10 java java-stream

我有一系列发票:

class Invoice {
  int month;
  BigDecimal amount
}
Run Code Online (Sandbox Code Playgroud)

我想合并这些发票,因此我每月收到一张发票​​,金额是本月发票金额的总和.

例如:

invoice 1 : {month:1,amount:1000}
invoice 2 : {month:1,amount:300}
invoice 3 : {month:2,amount:2000}
Run Code Online (Sandbox Code Playgroud)

输出:

invoice 1 : {month:1,amount:1300}
invoice 2 : {month:2,amount:2000}
Run Code Online (Sandbox Code Playgroud)

我怎么能用java 8流做到这一点?

编辑:因为我的Invoice类是可变的,修改它们不是问题,我选择了Eugene的解决方案

Collection<Invoice>  invoices = list.collect(Collectors.toMap(Invoice::getMonth, Function.identity(), (left, right) -> {
                left.setAmount(left.getAmount().add(right.getAmount()));
                return left;
            })).values();
Run Code Online (Sandbox Code Playgroud)

Eug*_*ene 21

如果你可以返回Collection它,它将如下所示:

Collection<Invoice>  invoices = list.collect(Collectors.toMap(Invoice::getMonth, Function.identity(), (left, right) -> {
                left.setAmount(left.getAmount().add(right.getAmount()));
                return left;
            })).values();
Run Code Online (Sandbox Code Playgroud)

如果你真的需要List:

 list.stream().collect(Collectors.collectingAndThen(Collectors.toMap(Invoice::getMonth, Function.identity(), (left, right) -> {
                left.setAmount(left.getAmount().add(right.getAmount()));
                return left;
            }), m -> new ArrayList<>(m.values())));
Run Code Online (Sandbox Code Playgroud)

两者都明显假设Invoice是可变的......

  • 嗨!2评论... 1)也许它应该是`list.stream().collect(...)`和2)你正在改变原来的`Invoice`元素,这对我来说看起来不正确......你可以通过添加复制构造函数并在值映射器中使用它来解决它 (2认同)

Fed*_*ner 8

如果您可以将以下复制构造函数和合并方法添加到您的Invoice类:

public Invoice(Invoice another) {
    this.month = another.month;
    this.amount = another.amount;
}

public Invoice merge(Invoice another) {
    amount = amount.add(another.amount); // BigDecimal is immutable
    return this;
}
Run Code Online (Sandbox Code Playgroud)

您可以根据需要减少,如下所示:

Collection<Invoice> result = list.stream()
    .collect(Collectors.toMap(
        Invoice::getMonth, // use month as key
        Invoice::new,      // use copy constructor => don't mutate original invoices
        Invoice::merge))   // merge invoices with same month
    .values();
Run Code Online (Sandbox Code Playgroud)

我正在使用Collectors.toMap这个工作,它有三个参数:一个将流的元素映射到键的函数,一个将流的元素映射到值的函数和一个用于在发生碰撞时组合值的合并函数按键.