如何使用Java8Collectors对三重嵌套映射求和



我有这个地图映射<LocalDate,映射<整数,映射<E四分之一小时,双倍>gt>

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,EHourQuaQuarter.SECOND->10.2,…},1->{EHourQuarter.FIRST->33.2,EHourQuaquarter.SECOND->30.1,…},…},

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

这是Double的EHourQuarter的映射的Integer(小时:从0到23(的映射的LocalDate的映射。

我需要得到一张地图<整数(小时(,映射<E四分之一小时,双倍>gt;包含每个日期的累计值,这意味着如果日期2020-07-07到2020-07-10(4天(包含在0小时中,则每个季度的结果应显示在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创建Stream<SimpleEntry<Integer, EHourQuarter>, Double>,然后使用toMap收集作为Map<SimpleEntry<Integer, EHourQuarter>, Double>。然后映射到DTO类中。

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

然后将分组条目映射到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();

最新更新