使用收集器按两个字段分组

时间:2019-01-23 18:50:41

标签: java java-8 java-stream collectors

我有一个Java对象Record:

.*

我将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分组,然后创建一个新的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对列表进行分组。因此,如果categoryday相同,我想像已经在做的那样,将category字段合并到一个新的amount中。我需要添加另一个Record子句,但是语法一直没有起作用。我相信返回类型将是Collectors.groupingBy。然后,我还需要将返回的地图转换为Map<ZonedDateTime, Map<String, List<Record>>>

我一直在尝试结束本示例Group by multiple field names in java 8

1 个答案:

答案 0 :(得分:4)

您可以使用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的{​​{1}}。 (Record.category根据需要实现ListObject.hashCode,因此可以安全地用作任何Object.equals的键)。

为简化工作,我们需要一个复制构造函数和一个Map方法:

merge

最后,要返回记录列表,不需要做任何比这更好的事情了:

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;
}