如何在流

时间:2017-03-17 05:07:16

标签: java dictionary java-stream reduce flatmap

假设txn流,其中每个txn具有以下字段

{date,amt,name,merchant}
给出txn流
     按yyyy-mm //折叠1
      在组内(yyyy-mm);映射到新对象费用(收入,支出)
            如果金额> 0然后收入+ = amt //条件折叠2.a
            如果金额< 0然后花费+ = amt //条件折叠2.b

我想知道在java中实现上述方法是什么。 尝试下面,它很短暂

    txns
                .stream()
                .collect(
                    Collectors.groupingBy(
                        Txn::getYearMonth, 
                        Collectors.mapping(
                            getExpense,
                            Collectors.toList()))); 

getexpense是我编写的函数映射,用于将Txn转换为Expense对象。

1 个答案:

答案 0 :(得分:0)

我认为你被困在了一步。您发布的代码将导致:

Map<YearMonth, List<Expense>>

虽然我猜你想要:

Map<YearMonth, Expense>  // transactions aggregated into a single Expense

为此,您需要创建一个可以聚合Expense个对象的收集器。

看起来像这样:

Collector.of(
  Expense::new,
  (Expense e, Transaction t) -> e.add(t),
  (e1, e2) -> new Expense(e1, e2)
);

您的费用等级需要:

  1. 公共空构造函数
  2. 一个需要2笔费用并创建新的汇总费用的构造函数
  3. add添加到Transaction
  4. Expense方法

    这样的事情:

    public class Expense {
      private double income;
      private double spent;
    
      public Expense() {
      }
    
      public Expense(Expense e1, Expense e2) {
        this.income = e1.income + e2.income;
        this.spent = e1.spent + e2.spent;
      }
    
      public void add(Transaction t) {
        this.income += t.getAmount() > 0 ? t.getAmount() : 0;
        this.spent += t.getAmount() < 0 ? t.getAmount() : 0;
      }
    }
    

    然后,您可以在groupingBy中使用此Collector

    groupingBy(Txn::getYearMonth, myCollector)
    

    结果将是单个Expense对象中的汇总费用。

    <强>更新

    所以这样:

    Collector<Transaction, Expense, Expense> c = Collector.of(
      Expense::new,
      (Expense e, Transaction t) -> e.add(t),
      (e1, e2) -> new Expense(e1, e2)
    );
    
    Map<YearMonth, Expense> collect = txns.stream()
        .collect(Collectors.groupingBy(Transaction::getYearMonth, c));