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

На данный момент я нахожусь получая ошибки, связанные с заменой всех (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. Группировка со стороны db всегда быстрее.

0

Если я правильно понимаю ваш вопрос: вы хотите группировать записи по названию компании и объединить транзакции с максимальным количеством кредитов/дебитом с одним и тем же именем клиента. Вот мое решение: 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()); 

 Смежные вопросы

  • Нет связанных вопросов^_^