将对象分组以创建扩展对象列表

4

我有这些来自数据库的样本记录,这是一个按照分组查询结果:

[
 {
   "name": "Troy",
   "acct": 1123,
   "type": " Savings",
   "total": 50
 },
 {
   "name": "Larry",
   "acct": 4233,
   "type": " Savings",
   "total": 200
 },
 {
   "name": "Troy",
   "acct": 1123,
   "type": " Current",
   "total": 120
 },
 {
   "name": "Larry",
   "acct": 4233,
   "type": " Current",
   "total": 220
 }
]

现在,我需要创建一个类似于这样的报告:
[
 {
   "name": "Troy",
   "acct": 1123,
   "totalSavings": 50,
   "totalCurrent": 120
 },
 {
   "name": "Larry",
   "acct": 4233,
   "totalSavings": 200,
   "totalCurrent": 220
 }
]

.

public class DbTrans {
    private String name;
    private String acct;
    private String type;
    private double total;

// getters and setters
...
}

我尝试使用一些lambda技术,如下所示,但仍未接近我想要的解决方案。
 Map<String, List<DbTrans>> collect = transList.stream().collect(
          Collectors.groupingBy(f -> f.getType()));
2个回答

5
首先,响应 Dto 不同于请求 Dto,我的建议是创建一个新的响应类,我们称之为:
public class DbTransResponse {
    private String name;
    private String acct;
    private double totalSavings;
    private double totalCurrent;
    // getters and setters
}

那么结果可能会是这样的:
List<DbTransResponse> result = transList.stream()
        .collect(Collectors.groupingBy(DbTrans::getAcct))
        .values().stream()
        .map(trans -> new DbTransResponse(
                trans.get(0).getName(),
                trans.get(0).getAcct(),
                trans.get(0).getTotal(),
                trans.get(1).getTotal()
        )).collect(Collectors.toList());

我认为列表应该包含每个名称的两个条目,这样你就可以从第一个条目trans.get(0).getTotal()获取totalSavings,并从第二个条目trans.get(1).getTotal()获取totalCurrent
如果您不确定,可以使用条件来填充对象,例如,您可以检查是否有两个元素,如果没有,则设置默认值。

Ideone演示

输出

DbTransResponse{name='Larry', acct='4233', totalSavings=200.0, totalCurrent=220.0}
DbTransResponse{name='Troy', acct='1123', totalSavings=50.0, totalCurrent=120.0}

可能我正在处理银行相关的工作 :) 但如果类型是交易类型,你的考虑是错误的,可能会有多个相同类型的交易。但这应该由Olantobi回答。 - Alexander Petrov
1
顺便说一下,按名称分组没有意义。账户唯一与个人相关联。因此,按帐号分组就足够了。除非它不是账户的所有者而是交易发起者,但我怀疑这一点。 - Alexander Petrov
2
@AlexandarPetrov 我同意第二条评论,按账户分组更好。至于第一条评论,如果OP想要按多个字段分组,那么使用.collect(Collectors.groupingBy(DbTrans::getName, Collectors.groupingBy(DbTrans::getAcct))) .values().stream() .flatMap(m -> m.values().stream())并不更容易。 - Youcef LAIDANI

2
你可以使用Collectors::toMap来实现此目的(通过单个collect操作)。"Original Answer"翻译成"最初的回答"。
 Map<Integer, DbTransResponse> collect = transList.stream()
            .collect(Collectors.toMap(DbTrans::getAcct, 
                                      DbTransResponse::new, 
                                      DbTransResponse::merge));

 Collection<DbTransResponse> result = collect.values();

DbTransResponse类中有一个合并方法,名为"merge"。原始回答即为"最初的回答"。
static DbTransResponse merge(DbTransResponse r1, DbTransResponse r2) {
        return new DbTransResponse(
                r1.name, r1.acct,
                r1.totalSavings + r2.totalSavings,
                r1.totalCurrent + r2.totalCurrent
        );
    }

还需要为DbTransResponse类添加一个额外的构造函数,不过你可以将这个逻辑移到一个方法中。


DbTransResponse(DbTrans dbTrans) {
   this.name = dbTrans.getName();
   this.acct = dbTrans.getAcct();
   this.totalSavings = "Savings".equals(dbTrans.getType()) ? dbTrans.getTotal() : 0;
   this.totalCurrent = "Current".equals(dbTrans.getType()) ? dbTrans.getTotal() : 0;

}

demo


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接