【问题标题】:How to use grouping, aggregate, transformation and filtering on stream如何在流上使用分组、聚合、转换和过滤
【发布时间】:2017-08-08 13:04:30
【问题描述】:

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

{ 日期、金额、姓名、商家 }
给定 txn 流
按 yyyy-mm 分组 // 折叠 1
组内(yyyy-mm);映射到新对象费用(收入,花费)
if amount > 0 then income+=amt // 条件折叠 2.a
if amount

我想知道在 java 中实现上述目标的方法是什么。 试了下,还是差了点

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

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

【问题讨论】:

    标签: java dictionary java-stream reduce flatmap


    【解决方案1】:

    我认为你被困在聚合步骤上。您发布的代码将导致:

    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 添加到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));
    

    【讨论】:

    • 请你帮我定义 myCollector
    • 我想,交易金额应该加到incomespent而不是覆盖它......
    • 是的,好像我错过了,更新它
    • @john16384 上面的代码无法编译,除非我更改为 belowCollector.of( Expense::new, (Expense e, Transaction t) -> e.add(t), (e1, e2) -> 新费用(e1,e2));
    • 在线下方出错收集器类型中的方法映射(Function super T,? extends U>, Collector super U,A,R>) 不适用于参数(Function , 收集器) TxnsController.java /deepak/src/main/java/com/example
    猜你喜欢
    • 2017-07-03
    • 1970-01-01
    • 1970-01-01
    • 2013-04-09
    • 2016-05-30
    • 1970-01-01
    • 2017-09-10
    • 1970-01-01
    • 2020-12-24
    相关资源
    最近更新 更多