已经有许多好的答案了。除此之外,我想再补充以下内容:
- 不要将字符串放在原始列表中。放置
LocalDate
对象。如果您获得字符串输入,请在添加到列表之前解析它。
- 您不需要对内部列表进行排序以获取其最小值(或最大值)。
在 Java 10 或更高版本中:
List<LocalDate> input = List.of(LocalDate.of(2019, 11, 4),
LocalDate.of(2019, 11, 11), LocalDate.of(2019, 11, 18),
LocalDate.of(2019, 11, 25), LocalDate.of(2019, 12, 2),
LocalDate.of(2019, 12, 9), LocalDate.of(2020, 1, 6),
LocalDate.of(2020, 2, 3), LocalDate.of(2020, 2, 10),
LocalDate.of(2020, 2, 17), LocalDate.of(2020, 2, 24),
LocalDate.of(2020, 3, 2), LocalDate.of(2020, 3, 9),
LocalDate.of(2020, 3, 16), LocalDate.of(2020, 3, 23),
LocalDate.of(2020, 3, 30), LocalDate.of(2020, 4, 6),
LocalDate.of(2020, 4, 13), LocalDate.of(2020, 4, 20),
LocalDate.of(2020, 4, 27));
List<LocalDate> minDatePerMonth = input.stream()
.collect(Collectors.groupingBy(YearMonth::from, Collectors.minBy(Comparator.naturalOrder())))
.values()
.stream()
.map(Optional::orElseThrow)
.sorted()
.collect(Collectors.toList());
我正在使用重载版本的
Collectors.groupingBy
,它接受一个“下游收集器”。
groupingBy
产生一个映射(map),但它的值不是列表,而是由下游收集器产生的。在这种情况下,我们使用
Collectors.minBy
,它会产生一个包含
Optional<LocalDate>
的结果。由于
groupingBy
不会创建没有至少一个日期的映射条目,所以我们知道
Optional
不能为空。
当然,我们希望为用户提供格式良好的输出。我们可以通过以下方式实现:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/uuuu");
String output = minDatePerMonth.stream()
.map(formatter::format)
.collect(Collectors.joining(", "));
System.out.println(output);
2019年4月11日,2019年2月12日,2020年6月1日,2020年3月2日,2020年2月3日,2020年4月6日
在 Java 9 中
Java 10 中引入了无参的 Optional.orElseThrow
。在 Java 8 和 9 中,您可以使用例如:
.map(old -> old.orElseThrow(() -> new IllegalStateException("This can’t happen")))
在Java 8中,
List.of
还未被引入。但是您已经获得了列表,因此我会考虑如何在问题之外进行初始化。如果需要,在Java 8中初始化列表的具体方法请读者自行寻找。