我对Java 8相对较新,并试图绕过流。 我从数据库中查询返回以下内容:
String companyName |
String clientName |
BigDecimal amount |
String transactionType (either credit or debit) |
long numberOfTransactions
我将每个行存储在此对象中,使用transactionType字段的值来确定哪个creditAmount或debitAmount量被填充
public RowForCsv{
private String companyName;
private String customerName;
private BigDecimal creditAmount;
private BigDecimal debitAmount;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((companyName == null) ? 0 : companyName.hashCode());
result = prime * result + ((customerName == null) ? 0 : customerName.hashCode());
return result;
}
}
我需要使用这些数据为与每个公司名称相关的交易制作单独的CSV文件,这意味着最终我想要
`Map<String companyName, List<RowForCsv> associatedTransactions>`
由于客户可以同时发放信用和借方,我还希望将具有相同客户和公司名称的单独RowForCsv对象合并到一个RowForCsv对象中。
以下是我尝试的内容:
//Get Map<name, list of transactions>
Map<String, List<ReconciliationRecordForCsv>> mapByCompanyName = records.stream().collect(Collectors.groupingBy(ReconciliationRecordForCsv::getCompanyName));
// Merge duplicates
mapByCompanyName.replaceAll((k, v) -> {
v.stream().collect(Collectors.collectingAndThen(
Collectors.groupingBy(RowForCsv::hashCode),
Collectors.collectingAndThen(Collectors.reducing((a, b) -> mergeCreditAndDebitRecords(a, b)), Optional::get)),
m -> new ArrayList<>(m.values()));
});
这是我的合并功能,我认为我误解了......的概念。
private RowForCsv mergeCreditAndDebitRecords(RowForCsv first, RowForCsv second) {
RowForCsv.Builder merged = new RowForCsv.Builder();
return merged.companyName(first.getCompanyName())
.customerName(first.getCustomerName())
.creditAmount(getLarger(first.getCreditAmount(), second.getCreditAmount()))
.debitAmount(getLarger(first.getDebitAmount(), second.getDebitAmount()))
.build();
}
此时我收到与没有类型的替换所有(k,v)有关的错误,collectAndThens都抛出与其链接相关的错误,并且合并函数对于类型无效(对象,对象)。
我有一种感觉,我以错误的方式接近这一点,但我不知道自己应该采取哪些不同的做法,任何指导都会受到高度赞赏。
答案 0 :(得分:1)
我认为这可能是一个解决方案:
final Map<String, List<Optional<RowForCsv>>> collect1 =
rows.stream().collect(Collectors.groupingBy(RowForCsv::getCompanyName, Collectors.collectingAndThen(Collectors.toList(), byBank -> {
return byBank.stream() //
.collect(Collectors.groupingBy(RowForCsv::getCustomerName)).values().stream()
.map(byUser -> byUser.stream().reduce((r1, r2) -> r2)).collect(Collectors.toList()); //
})));
另一种方法可能是&#34;减少&#34;初始行,以便每个用户拥有唯一的行,然后是groupBy公司。
如果我有更多时间,我会回到这里。有趣的问题。也许你可以尝试从db改进你的查询。从数据库侧进行分组总是更快。
答案 1 :(得分:0)
如果我正确理解您的问题:您希望按公司名称按记录分组,并使用相同的客户名称合并最大creditAmount / debitAmount的交易。这是AbacusUtil
的解决方案// merge two records with same customer name by using the maximum creditAmount/debitAmount
BinaryOperator<RowForCsv> mergeFunction = (a, b) -> {
RowForCsv c = new RowForCsv();
c.companyName = a.companyName;
c.customerName = a.customerName;
c.creditAmount = N.max(a.creditAmount, b.creditAmount);
c.debitAmount = N.max(a.creditAmount, b.creditAmount);
return c;
};
Map<String, Collection<RowForCsv>> mergedAmountByCompanyName =
Stream.of(records).groupBy(e -> e.getCompanyName())
.toMap(e -> e.getKey(),
e -> Stream.of(e.getValue())
.toMap(e2 -> e2.getCustomerName(), e2 -> e2, mergeFunction).values());