gpt4 book ai didi

java - Collectors.groupingBy 进入对象列表?

转载 作者:行者123 更新时间:2023-11-30 03:05:14 26 4
gpt4 key购买 nike

给定一个 TimeEntry 对象列表,我想将它们分组为 Day 和 Hour 对象。

其中 Day 有 Hour 对象的列表,而 Hour 有其代表的小时的 TimeEntry 对象的列表。

Day 和 Hour 还保留各自列表中 TimeEntry 持续时间的总和。如果可能的话,也将日期名称放入 Day 中。 TimeEntry 列表按“开始”排序。

public class TimeEntry {
private LocalDateTime start;
private Duration duration;

public Integer getDay() { return this.start.get(ChronoField.DAY_OF_MONTH); }
public Integer getHour() { return this.start.get(ChronoField.HOUR_OF_DAY); }
public String getDayName() {
return this.start.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.getDefault());
}
}

public class Day {
private Integer dayNr;
private String dayName;
private Duration sumOfHours;
private List<Hour> hours;
}

public class Hour {
private Integer hourNr;
private Duration sumOfEntries;
private List<TimeEntry> entries;
}

如何使用 Java 8 的流来做到这一点?

List<Day> days = timeEntries.stream().collect(Collectors.groupingBy(...? 

示例输入:

List<TimeEntry> timeEntries = [{"2016-01-22 10:00", "5 minutes"}, 
{"2016-01-23 08:00", "7 minutes"} , {"2016-01-23 08:43", "3 minutes"}]

示例输出:

[
{dayNr: 22, dayName: Friday, sumofEntries: 5 minutes
[{hourNr: 10, sumofEntries: 5 minutes},
[{"2016-01-22 10:00", "5 minutes"}]} ]},
{dayNr: 23, dayName: Saturday, sumofEntries: 10 minutes
[{hourNr: 8, sumofEntries: 10 minutes},
[{"2016-01-23 08:00", "7 minutes"},
{"2016-01-23 08:43", "3 minutes"} ]}
]

最佳答案

这是一个相当复杂的操作。直接的方法是首先创建一个 Map<Integer, Map<Integer, List<TimeEntry>>>按天分组,然后按小时分组。一旦我们有了该 map ,我们就可以对其进行后处理以创建所需的 List<Day> .

创建临时 map 非常简单。我们可以使用 Collectors.groupingBy(classifier, downstream) 其中分类器返回日期(通过方法引用 TimeEntry::getDay ),下游收集器是另一个 groupingBy收集器在几个小时内进行分类(通过方法引用 TimeEntry::getHour )。在此步骤之后,我们将获得每天的 map ,其中值是每小时的 map ,映射到相应的时间条目。

接下来,我们需要做的是 List<Day>从那张 map 中出来。基本上,映射的每个条目(因此每天的编号)都必须映射到相应的Day。对象。

  • dayNr只是条目的关键。
  • dayName是当天和一小时的时间条目之一的日期名称。由于我们之前按这些字段进行分组,因此必须存在一个时间条目:为了检索它,我们获取小时 map Map<Integer, List<TimeEntry>>对于当天的数字,只保留第一个值。
  • hours可以通过操作小时图来检索Map<Integer, List<TimeEntry>>为当天的号码。对于该 map 的每个条目:
    • hourNr只是条目的关键
    • entries字段是条目的值
    • sumOfEntries是该小时数的所有时间条目持续时间的总和。
  • 最后,sumOfHours是所有 sumOfEntries 的相加对应当天数字的每个小时数字。

完整的实现如下,假设所有域对象都有适当的构造函数和适当的 getter:

public static void main(String[] args) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
List<TimeEntry> timeEntries = Arrays.asList(
new TimeEntry(LocalDateTime.parse("2016-01-22 10:00", formatter), Duration.ofMinutes(5)),
new TimeEntry(LocalDateTime.parse("2016-01-23 08:00", formatter), Duration.ofMinutes(7)),
new TimeEntry(LocalDateTime.parse("2016-01-23 08:43", formatter), Duration.ofMinutes(3))
);

Map<Integer, Map<Integer, List<TimeEntry>>> map =
timeEntries.stream()
.collect(groupingBy(TimeEntry::getDay, groupingBy(TimeEntry::getHour)));

List<Day> output =
map.entrySet()
.stream()
.map(e -> {
String dayName = e.getValue().values().iterator().next().get(0).getDayName();
List<Hour> hours =
e.getValue().entrySet()
.stream()
.map(he -> new Hour(he.getKey(), sumDuration(he.getValue(), TimeEntry::getDuration), he.getValue()))
.collect(toList());
return new Day(e.getKey(), dayName, sumDuration(hours, Hour::getSumOfEntries), hours);
})
.collect(toList());

System.out.println(output);
}

private static <T> Duration sumDuration(List<T> list, Function<T, Duration> function) {
return list.stream().map(function::apply).reduce(Duration.ofMinutes(0), (d1, d2) -> d1.plus(d2));
}

请注意添加 Duration列表中的对象被纳入辅助方法 sumDuration .

以上示例的输出(假设 toString() 打印方括号内的所有字段):

[Day [dayNr=22, dayName=vendredi, sumOfHours=PT5M, hours=[Hour [hourNr=10, sumOfEntries=PT5M, entries=[TimeEntry [start=2016-01-22T10:00, duration=PT5M]]]]], Day [dayNr=23, dayName=samedi, sumOfHours=PT10M, hours=[Hour [hourNr=8, sumOfEntries=PT10M, entries=[TimeEntry [start=2016-01-23T08:00, duration=PT7M], TimeEntry [start=2016-01-23T08:43, duration=PT3M]]]]]]

关于java - Collectors.groupingBy 进入对象列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34975660/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com