Конвертировать картуна карту>> используя API Java Stream - PullRequest
1 голос
/ 13 марта 2019

Я получаю несколько наборов результатов из базы данных и сохраняю каждую строку как объект типа DbRow, это класс:

public class DbRow {

    private int clientNumber;
    private String recordNumber;
    private String takeoverMonth;
    private int takeovers;
    private int mainClaims;
    private int distinctContractDates;
    private LocalDate contractDate;

    public DbRow(int clientNumber, String recordNumber, String takeoverMonth, int takeovers,
                int mainClaims, int distinctContractDates, LocalDate contractDate) {
        super();
        this.clientNumber = clientNumber;
        this.recordNumber = recordNumber;
        this.takeoverMonth = takeoverMonth;
        this.takeovers = takeovers;
        this.mainClaims = mainClaims;
        this.distinctContractDates = distinctContractDates;
        this.contractDate = contractDate;
    }

    // getters & setters

    // hashCode, equals & toString
}

В настоящее время я сохраняю полученные объекты в Map<Integer, List<DbRow>>, чтобы разделить их определенным свойством (в данном случае clientNumber, все DbRow с определенным номером клиента хранятся в List<DbRow>> * в то время как их ключ - это определенный номер клиента).

Мне нужно создать из него Map<Integer, Map<String, Map<LocalDate, Integer>>>, что я сейчас делаю, используя много строк кода.

Желаемый результат можно описать как
количество различных контрактных дат за месяц поглощения на номер клиента
(например, Map< номер клиента , Map< месяц захвата , Map< дата контракта , количество >>>)
где месяцем поглощения является String формата "yyyy/MM".

Мое текущее решение безобразно, но работает. Он содержит создание и заполнение вложенных карт, а также проверку существующих ключей, от которых я хочу избавиться. Пожалуйста, посмотрите на это:

Map<Integer, List<DbRow>> records = new TreeMap<>();

// fill records with database results ...

Map<Integer, Map<String, Map<LocalDate, Integer>>> results = new TreeMap<>();

records.forEach((clientNumber, dbRows) -> {
    Map<String, List<DbRow>> rowsPerMonth = dbRows.stream()
                    .collect(Collectors.groupingBy(DbRow::getTakeoverMonth));
    Map<String, Map<LocalDate, Integer>> monthResults = new TreeMap<>();

    rowsPerMonth.forEach((takeoverMonth, rows) -> {
        if (monthResults.containsKey(takeoverMonth)) {
            Map<LocalDate, Integer> contractDateCount = monthResults.get(takeoverMonth);
            rows.forEach(dbRow -> {
                LocalDate contractDate = dbRow.getContractDate();
                if (contractDateCount.containsKey(contractDate)) {
                    int count = contractDateCount.get(contractDate);
                    count++;
                    contractDateCount.put(contractDate, count);
                } else {
                    contractDateCount.put(contractDate, 1);
                }
            });
            monthResults.put(takeoverMonth, contractDateCount);
        } else {
            Map<LocalDate, Integer> contractDateCount = new TreeMap<>();
            rows.forEach(dbRow -> {
                LocalDate contractDate = dbRow.getContractDate();
                if (contractDateCount.containsKey(contractDate)) {
                    int count = contractDateCount.get(contractDate);
                    count++;
                    contractDateCount.put(contractDate, count);
                } else {
                    contractDateCount.put(contractDate, 1);
                }
            });
            monthResults.put(takeoverMonth, contractDateCount);
        }
    });

    results.put(clientNumber, monthResults);
});

Кто-нибудь знает (если есть) способ сделать это более коротким способом, используя потоковый API? Я действительно хочу иметь красивое решение для этого.

1 Ответ

2 голосов
/ 13 марта 2019

Вы можете искать что-то вроде:

Map<Integer, Map<String, Map<LocalDate, Long>>>  countDistinctDatesPerMonthPerClient(List<DbRow> input) {
    return input.stream()
            .collect(Collectors.groupingBy(DbRow::getClientNumber,
                    Collectors.groupingBy(DbRow::getTakeoverMonth,
                            Collectors.groupingBy(DbRow::getContractDate, Collectors.counting()))));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...