2017-02-17 72 views
1

我对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(); 
} 

在这一点上,我获取有关替换all(k,v)没有类型的错误,collectAndThens都抛出与它们的链相关的错误,并且合并函数对类型(Object,Object)无效。

我有一种感觉,我正在接近这个错误的方式,但我没有看到我应该做什么不同,任何指导将不胜感激。

回答

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()); // 
      }))); 

另一种方法可以让你有每个用户唯一行,然后GROUPBY公司以“减少”的初始行。

如果我有更多的时间,我会回到这个。有趣的问题tho。也许你可以尝试从db中改进你的查询。从数据库方面分组总是更快。

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());