Группировка по двум полям с использованием коллекторов - PullRequest
0 голосов
/ 23 января 2019

У меня есть объект Java. Запись:

public Record(ZonedDateTime day, int ptid, String name, String category, int amount) {
        this.day= day;
        this.id= id;
        this.name = name;
        this.category = category;
        this.amount = amount;
}

Я группирую список Record s по их day, а затем создаю новый Record, который объединяет amountполе и возвращает карту:

Map<ZonedDateTime, Record> map = tempList.stream().collect(Collectors.groupingBy(Record::getDay,
                Collectors.collectingAndThen(
                        Collectors.reducing((r1, r2) -> new Record(r1.getDay(),Integer.toString(r1.getId),r1.getName(),
                                r1.getCategory(),r1.getAmount() + r2.getAmount())),
                        Optional::get)));

Я хочу сгруппировать список по day AND category.Поэтому, если day и category одинаковы, я бы хотел объединить поле amount в новом Record, как я уже делаю.Мне нужно добавить еще одно предложение Collectors.groupingBy, но синтаксис просто не работает.Я считаю, что тип возвращаемого значения будет Map<ZonedDateTime, Map<String, List<Record>>>.Затем мне также нужно преобразовать возвращенную карту в List.

Я пытался отключить этот пример Группировать по нескольким именам полей в Java 8

1 Ответ

0 голосов
/ 23 января 2019

Вы можете упростить всю конструкцию, используя Collectors.toMap:

Map<List<Object>, Record> map = tempList.stream()
        .collect(Collectors.toMap(
                            r -> List.of(r.getDay(), r.getCategory()), // or Arrays.asList
                            Record::new,
                            Record::merge));

Хитрость заключается в группировании по составному ключу.В этом случае мы используем List<Object> с Record.day и Record.category.(List реализует Object.hashCode и Object.equals по мере необходимости, поэтому его можно безопасно использовать в качестве ключа любого Map).

Чтобы сокращение работало, нам нужен конструктор копирования иmerge method:

public Record(Record r) {
    this(r.day, r.name, r.name, r.category, r.amount);
}

public Record merge(Record r) {
    this.amount += r.amount;
    return this;
}

Наконец, чтобы вернуть список записей, нет необходимости делать что-то более изумительное, чем это:

List<Record> result = new ArrayList<>(map.values());
...