如何使用Java 8收集器对三重嵌套映射求和

如何使用Java 8收集器对三重嵌套映射求和,java,java-8,java-stream,collectors,Java,Java 8,Java Stream,Collectors,我有这张地图 地图 EHourQuarter是一个枚举: public enum EHourQuarter { FIRST(0, 14, 15), SECOND(15, 29, 30), THIRD(30, 44, 45), FOURTH(45, 59, 60); private Integer start; private Integer end; private Integer value;//this is for UI purpo

我有这张地图 地图

EHourQuarter是一个枚举:

public enum EHourQuarter {
    FIRST(0, 14, 15),
    SECOND(15, 29, 30),
    THIRD(30, 44, 45),
    FOURTH(45, 59, 60);

    private Integer start;
    private Integer end;
    private Integer value;//this is for UI purposes
}
价值观如下: {2020-07-07->{0->{EHourQuarter.FIRST->5.5,EHourQuarter.SECOND->10.2,…}, 1->{EHourQuarter.FIRST->33.2,EHourQuarter.SECOND->30.1,…},…}

2020-07-08->{0->{EHourQuarter.FIRST->5.5,EHourQuarter.SECOND->10.2,…}, 1->{EHourQuarter.FIRST->33.2,EHourQuarter.SECOND->30.1,…}

这是一个LocalDate的映射,一个整数映射(小时:从0到23)的映射,一个EHourQuarter的映射

我需要得到一张包含每个日期累计值的地图,这意味着如果日期2020-07-07到2020-07-10(4天)包含在0小时内,每个季度5个小时,那么结果应该显示在0小时内,每个季度的值为20

另外,如果你能帮我把它映射到像这样的DTO列表中

public class QuarterlyOccupancyDTO {
    private Integer hour;
    private Integer minute;//this is the value property of EHourQuarter
    private Double occupancy;
}
我非常感激

最后,DTO列表应包含按小时和分钟分组的所有日期的总和(EHourQuarter的value属性)

这是一个例子

注意:地图可以包含多个日期,目的是对所有日期进行分组/求和。

根据这张地图:

{
   "2020-06-26":{
      "0":{
         "FOURTH":0.0,
         "FIRST":0.0,
         "THIRD":0.0,
         "SECOND":0.0
      },
      "1":{
         "FOURTH":0.0,
         "FIRST":0.0,
         "THIRD":0.0,
         "SECOND":0.0
      },
      "2":{
         "FOURTH":0.0,
         "FIRST":0.0,
         "THIRD":0.0,
         "SECOND":0.0
      },
      "3":{
         "FOURTH":0.0,
         "FIRST":0.0,
         "THIRD":0.0,
         "SECOND":0.0
      },
      "4":{
         "FOURTH":0.0,
         "FIRST":0.0,
         "THIRD":0.0,
         "SECOND":0.0
      },
      "5":{
         "FOURTH":0.0,
         "FIRST":0.0,
         "THIRD":0.0,
         "SECOND":0.0
      },
      "6":{
         "FOURTH":0.0,
         "FIRST":0.0,
         "THIRD":0.0,
         "SECOND":0.0
      },
      "7":{
         "FOURTH":0.0,
         "FIRST":0.0,
         "THIRD":0.0,
         "SECOND":0.0
      },
      "8":{
         "FOURTH":0.0,
         "FIRST":0.0,
         "THIRD":0.0,
         "SECOND":0.0
      },
      "9":{
         "FOURTH":5.0,
         "FIRST":5.0,
         "THIRD":5.0,
         "SECOND":5.0
      },
      "10":{
         "FOURTH":5.0,
         "FIRST":5.0,
         "THIRD":5.0,
         "SECOND":5.0
      },
      "11":{
         "FOURTH":5.0,
         "FIRST":5.0,
         "THIRD":5.0,
         "SECOND":5.0
      },
      "12":{
         "FOURTH":5.0,
         "FIRST":5.0,
         "THIRD":5.0,
         "SECOND":5.0
      },
      "13":{
         "FOURTH":5.0,
         "FIRST":5.0,
         "THIRD":5.0,
         "SECOND":5.0
      },
      "14":{
         "FOURTH":5.0,
         "FIRST":5.0,
         "THIRD":5.0,
         "SECOND":5.0
      },
      "15":{
         "FOURTH":5.0,
         "FIRST":5.0,
         "THIRD":5.0,
         "SECOND":5.0
      },
      "16":{
         "FOURTH":5.0,
         "FIRST":5.0,
         "THIRD":5.0,
         "SECOND":5.0
      },
      "17":{
         "FOURTH":5.0,
         "FIRST":5.0,
         "THIRD":5.0,
         "SECOND":5.0
      },
      "18":{
         "FOURTH":0.0,
         "FIRST":5.0,
         "THIRD":0.0,
         "SECOND":0.0
      },
      "19":{
         "FOURTH":0.0,
         "FIRST":0.0,
         "THIRD":0.0,
         "SECOND":0.0
      },
      "20":{
         "FOURTH":0.0,
         "FIRST":0.0,
         "THIRD":0.0,
         "SECOND":0.0
      },
      "21":{
         "FOURTH":0.0,
         "FIRST":0.0,
         "THIRD":0.0,
         "SECOND":0.0
      },
      "22":{
         "FOURTH":0.0,
         "FIRST":0.0,
         "THIRD":0.0,
         "SECOND":0.0
      },
      "23":{
         "FOURTH":0.0,
         "FIRST":0.0,
         "THIRD":0.0,
         "SECOND":0.0
      }
   }
}
答案应该是这样的列表:

[
   {
      "hour":0,
      "minute":15,
      "occupancy":0.0
   },
   {
      "hour":0,
      "minute":30,
      "occupancy":0.0
   },
   {
      "hour":0,
      "minute":45,
      "occupancy":0.0
   },
   {
      "hour":0,
      "minute":60,
      "occupancy":0.0
   },
   {
      "hour":1,
      "minute":15,
      "occupancy":0.0
   },
   {
      "hour":1,
      "minute":30,
      "occupancy":0.0
   },
   {
      "hour":1,
      "minute":45,
      "occupancy":0.0
   },
   {
      "hour":1,
      "minute":60,
      "occupancy":0.0
   },
   {
      "hour":2,
      "minute":15,
      "occupancy":0.0
   },
   {
      "hour":2,
      "minute":30,
      "occupancy":0.0
   },
   {
      "hour":2,
      "minute":45,
      "occupancy":0.0
   },
   {
      "hour":2,
      "minute":60,
      "occupancy":0.0
   },
   {
      "hour":3,
      "minute":15,
      "occupancy":0.0
   },
   {
      "hour":3,
      "minute":30,
      "occupancy":0.0
   },
   {
      "hour":3,
      "minute":45,
      "occupancy":0.0
   },
   {
      "hour":3,
      "minute":60,
      "occupancy":0.0
   },
   {
      "hour":4,
      "minute":15,
      "occupancy":0.0
   },
   {
      "hour":4,
      "minute":30,
      "occupancy":0.0
   },
   {
      "hour":4,
      "minute":45,
      "occupancy":0.0
   },
   {
      "hour":4,
      "minute":60,
      "occupancy":0.0
   },
   {
      "hour":5,
      "minute":15,
      "occupancy":0.0
   },
   {
      "hour":5,
      "minute":30,
      "occupancy":0.0
   },
   {
      "hour":5,
      "minute":45,
      "occupancy":0.0
   },
   {
      "hour":5,
      "minute":60,
      "occupancy":0.0
   },
   {
      "hour":6,
      "minute":15,
      "occupancy":0.0
   },
   {
      "hour":6,
      "minute":30,
      "occupancy":0.0
   },
   {
      "hour":6,
      "minute":45,
      "occupancy":0.0
   },
   {
      "hour":6,
      "minute":60,
      "occupancy":0.0
   },
   {
      "hour":7,
      "minute":15,
      "occupancy":0.0
   },
   {
      "hour":7,
      "minute":30,
      "occupancy":0.0
   },
   {
      "hour":7,
      "minute":45,
      "occupancy":0.0
   },
   {
      "hour":7,
      "minute":60,
      "occupancy":0.0
   },
   {
      "hour":8,
      "minute":15,
      "occupancy":0.0
   },
   {
      "hour":8,
      "minute":30,
      "occupancy":0.0
   },
   {
      "hour":8,
      "minute":45,
      "occupancy":0.0
   },
   {
      "hour":8,
      "minute":60,
      "occupancy":0.0
   },
   {
      "hour":9,
      "minute":15,
      "occupancy":5.0
   },
   {
      "hour":9,
      "minute":30,
      "occupancy":5.0
   },
   {
      "hour":9,
      "minute":45,
      "occupancy":5.0
   },
   {
      "hour":9,
      "minute":60,
      "occupancy":5.0
   },
   {
      "hour":10,
      "minute":15,
      "occupancy":5.0
   },
   {
      "hour":10,
      "minute":30,
      "occupancy":5.0
   },
   {
      "hour":10,
      "minute":45,
      "occupancy":5.0
   },
   {
      "hour":10,
      "minute":60,
      "occupancy":5.0
   },
   {
      "hour":11,
      "minute":15,
      "occupancy":5.0
   },
   {
      "hour":11,
      "minute":30,
      "occupancy":5.0
   },
   {
      "hour":11,
      "minute":45,
      "occupancy":5.0
   },
   {
      "hour":11,
      "minute":60,
      "occupancy":5.0
   },
   {
      "hour":12,
      "minute":15,
      "occupancy":5.0
   },
   {
      "hour":12,
      "minute":30,
      "occupancy":5.0
   },
   {
      "hour":12,
      "minute":45,
      "occupancy":5.0
   },
   {
      "hour":12,
      "minute":60,
      "occupancy":5.0
   },
   {
      "hour":13,
      "minute":15,
      "occupancy":5.0
   },
   {
      "hour":13,
      "minute":30,
      "occupancy":5.0
   },
   {
      "hour":13,
      "minute":45,
      "occupancy":5.0
   },
   {
      "hour":13,
      "minute":60,
      "occupancy":5.0
   },
   {
      "hour":14,
      "minute":15,
      "occupancy":5.0
   },
   {
      "hour":14,
      "minute":30,
      "occupancy":5.0
   },
   {
      "hour":14,
      "minute":45,
      "occupancy":5.0
   },
   {
      "hour":14,
      "minute":60,
      "occupancy":5.0
   },
   {
      "hour":15,
      "minute":15,
      "occupancy":5.0
   },
   {
      "hour":15,
      "minute":30,
      "occupancy":5.0
   },
   {
      "hour":15,
      "minute":45,
      "occupancy":5.0
   },
   {
      "hour":15,
      "minute":60,
      "occupancy":5.0
   },
   {
      "hour":16,
      "minute":15,
      "occupancy":5.0
   },
   {
      "hour":16,
      "minute":30,
      "occupancy":5.0
   },
   {
      "hour":16,
      "minute":45,
      "occupancy":5.0
   },
   {
      "hour":16,
      "minute":60,
      "occupancy":5.0
   },
   {
      "hour":17,
      "minute":15,
      "occupancy":5.0
   },
   {
      "hour":17,
      "minute":30,
      "occupancy":5.0
   },
   {
      "hour":17,
      "minute":45,
      "occupancy":5.0
   },
   {
      "hour":17,
      "minute":60,
      "occupancy":5.0
   },
   {
      "hour":18,
      "minute":15,
      "occupancy":5.0
   },
   {
      "hour":18,
      "minute":30,
      "occupancy":0.0
   },
   {
      "hour":18,
      "minute":45,
      "occupancy":0.0
   },
   {
      "hour":18,
      "minute":60,
      "occupancy":0.0
   },
   {
      "hour":19,
      "minute":15,
      "occupancy":0.0
   },
   {
      "hour":19,
      "minute":30,
      "occupancy":0.0
   },
   {
      "hour":19,
      "minute":45,
      "occupancy":0.0
   },
   {
      "hour":19,
      "minute":60,
      "occupancy":0.0
   },
   {
      "hour":20,
      "minute":15,
      "occupancy":0.0
   },
   {
      "hour":20,
      "minute":30,
      "occupancy":0.0
   },
   {
      "hour":20,
      "minute":45,
      "occupancy":0.0
   },
   {
      "hour":20,
      "minute":60,
      "occupancy":0.0
   },
   {
      "hour":21,
      "minute":15,
      "occupancy":0.0
   },
   {
      "hour":21,
      "minute":30,
      "occupancy":0.0
   },
   {
      "hour":21,
      "minute":45,
      "occupancy":0.0
   },
   {
      "hour":21,
      "minute":60,
      "occupancy":0.0
   },
   {
      "hour":22,
      "minute":15,
      "occupancy":0.0
   },
   {
      "hour":22,
      "minute":30,
      "occupancy":0.0
   },
   {
      "hour":22,
      "minute":45,
      "occupancy":0.0
   },
   {
      "hour":22,
      "minute":60,
      "occupancy":0.0
   },
   {
      "hour":23,
      "minute":15,
      "occupancy":0.0
   },
   {
      "hour":23,
      "minute":30,
      "occupancy":0.0
   },
   {
      "hour":23,
      "minute":45,
      "occupancy":0.0
   },
   {
      "hour":23,
      "minute":60,
      "occupancy":0.0
   }
]

首先使用
flatMap
create
Stream
,然后使用
toMap
collect as
Map
。然后将数据映射到类中

List<QuarterlyOccupancyDTO> result = map.entrySet().stream()
        .flatMap(d -> d.getValue().entrySet().stream()
            .flatMap(h -> h.getValue().entrySet().stream().map(
                e -> new SimpleEntry<>(new SimpleEntry<>(h.getKey(), e.getKey()), e.getValue()))))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a + b))
        .entrySet()
        .stream()
        .map(m -> new QuarterlyOccupancyDTO(m.getKey().getKey(), m.getKey().getValue().getValue(), m.getValue()))
        .collect(Collectors.toList());
List result=map.entrySet().stream()
.flatMap(d->d.getValue().entrySet().stream())
.flatMap(h->h.getValue().entrySet().stream().map(
e->new SimpleEntry(新SimpleEntry(h.getKey(),e.getKey(),e.getValue()))
.collect(Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue,(a,b)->a+b))
.entrySet()
.stream()
.map(m->new QuarterlyOccupancydo(m.getKey().getKey(),m.getKey().getValue().getValue(),m.getValue())
.collect(Collectors.toList());

注意:由于您没有显示代码,某些部分可能无法工作。完整代码为第一组,并按小时/季度对占用率求和

(避免嵌套的
flatMap
,因为它会降低代码的可读性)

映射组
=map.entrySet()
.stream()
//展平外部地图,因为你不在乎日子
.flatMap(de->de.getValue().entrySet().stream())
//通过将小时键和四分之一键组合为一个键来展平地图
.flatMap(he->he.getValue()
.entrySet()
.stream()
.map(qe->new simplentry(new simplentry(he.getKey()、qe.getKey().getValue()、qe.getValue()))
//每小时/每季度入住率总和
.collect(groupingBy(Entry::getKey,summingDouble(Entry::getValue));
然后将分组的条目映射到DTO对象中

List<QuarterlyOccupancyDTO> list =
    groups.entrySet()
          .stream()
          .map(e -> new QuarterlyOccupancyDTO(e.getKey().getKey(), e.getKey().getValue(), e.getValue()))
          .collect(toList());
列表=
groups.entrySet()
.stream()
.map(e->new QuarterlyOccupancydo(e.getKey().getKey(),e.getKey().getValue(),e.getValue())
.collect(toList());

另一种纯功能方法:

(在我看来,这很纯粹,但可读性较差)

集合DTO=
map.entrySet()
.stream()
//展平外部地图,因为你不在乎日子
.flatMap(de->de.getValue().entrySet())
.stream())
//通过将小时键和四分之一键合并为一个键来展平地图
.flatMap(he->he.getValue()
.entrySet()
.stream()
.map(qe->new simplentry(new simplentry(he.getKey(),qe.getKey().getValue()),
qe.getValue())
//将每个条目映射到DTO对象中,然后减少每小时/每季度的占用率
.收集(
groupingBy(条目::getKey,
映射(e->new QuarterlyOccupancydo(e.getKey().getKey(),e.getKey().getValue(),e.getValue()),
将(新的四分之一)还原为(0,0,0.0),
(a,b)->新的QuarterlyOccupPancydo(b.getHour(),b.getMinute(),a.GetOccupation()+b.GetOccupation())())
.values();

在Post中添加您迄今为止尝试过的方法您的解决方案与其他答案有什么区别?@RiwimoHerbs 1.不要使用嵌套的flatmapping。2.
summingDouble
而不是使用合并函数。3.中间变量而不是链接两条管道(微小更改)大部分想法都是一样的,你只是做了一些小的改变,最好是评论来更新小的改变。希望你能理解。@RiwimoHerbs你的投票权属于你。无论你想怎么投,都可以随时投。谢谢你的回答,我同意这更具可读性,谢谢你的回答,我想我会使用另一种选择因为我觉得它更具可读性,所以被ETO拒绝了
List<QuarterlyOccupancyDTO> list =
    groups.entrySet()
          .stream()
          .map(e -> new QuarterlyOccupancyDTO(e.getKey().getKey(), e.getKey().getValue(), e.getValue()))
          .collect(toList());
Collection<QuarterlyOccupancyDTO> dtos =
    map.entrySet()
       .stream()
       // Flatten the outer map, since you don't care about the days
       .flatMap(de -> de.getValue().entrySet()
                        .stream())
       // Flatten the map by merging hour key and quarter key into a single one
       .flatMap(he -> he.getValue()
                        .entrySet()
                        .stream()
                        .map(qe -> new SimpleEntry<>(new SimpleEntry<>(he.getKey(), qe.getKey().getValue()),
                                                     qe.getValue())))
       // Map each entry into a DTO object and then reduce the occupancy per each hour/quarter pair
       .collect(
           groupingBy(Entry::getKey,
                      mapping(e -> new QuarterlyOccupancyDTO(e.getKey().getKey(), e.getKey().getValue(), e.getValue()),
                              reducing(new QuarterlyOccupancyDTO(0, 0, 0.0),
                                       (a, b) -> new QuarterlyOccupancyDTO(b.getHour(), b.getMinute(), a.getOccupancy() + b.getOccupancy())))))
       .values();