2017-02-17 74 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());