簡體   English   中英

如何將三重嵌套 map 與 Java 8 個收集器相加

[英]How to sum a triple nested map with Java 8 Collectors

我有這個 map Map<LocalDate, Map<Integer, Map<EHourQuarter, Double>>>

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, . ..}, ... }

It's a map of LocalDate of map of Integer (hour: from 0 to 23) of map of EHourQuarter of Double.

我需要得到一個包含每個日期累積的 Map<Integer(hour), Map<EHourQuarter, Double>>,這意味着如果日期 2020-07-07 到 2020-07-10(4 天)包含在小時 0每個 EHourQuarter 每一個 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 屬性)。

這是一個例子。

注意:map 可以包含多個日期,目的是對所有日期進行分組/求和。

鑒於此 map:

{
   "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創建Stream<SimpleEntry<Integer, EHourQuarter>, Double>然后使用toMap collect as Map<SimpleEntry<Integer, EHourQuarter>, Double> 然后 map 進入你的 DTO class。

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());

注意:由於您沒有顯示代碼,因此某些部分可能無法正常工作。 完整代碼在這里

第一組並按小時/季度對合計占用率

(避免嵌套flatMap ,因為它降低了代碼的可讀性)

Map<Entry<Integer, Integer>, Double> groups
    = 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 combining 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())))
         // Sum the occupancy per each hour/quarter pair
         .collect(groupingBy(Entry::getKey, summingDouble(Entry::getValue)));

然后 map 將分組條目放入您的 DTO 對象

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

另一種純函數方法:

(它是純粹的,但似乎不太可讀,IMO)

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();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM