如何从给定的日期集中找到每个月的最少日期

时间:2019-11-14 07:51:24

标签: java sorting date

我需要从每个提到的月份的给定日期数组中提取最少的日期。

示例-日期格式为dd / MM / yyyy 以下是示例输入

04/11/2019,  11/11/2019, 18/11/2019, 25/11/2019, 02/12/2019, 09/12/2019, 
06/01/2020, 03/02/2020, 10/02/2020, 17/02/2020, 24/02/2020, 02/03/2020, 
09/03/2020, 16/03/2020, 23/03/2020, 30/03/2020, 06/04/2020, 13/04/2020, 
20/04/2020, 27/04/2020

我需要从每个月获取最少的日期:

输出类似-

04/11/2019, 02/12/2019, 06/01/2020, 03/02/2020, 02/03/2020, 06/04/2020

有人可以帮忙吗?

5 个答案:

答案 0 :(得分:5)

如果您使用的是Java-8,则可以使用:

List<LocalDate> collect = Stream.of(strings)
        .map(s -> LocalDate.parse(s, format)) // convert your strings to LocalDate
        .collect(Collectors.groupingBy(YearMonth::from)) // group by year and month
        .values().stream()
        .map(a -> a.stream().sorted().limit(1).findFirst().get())
        .sorted()
        .collect(Collectors.toList()); // collect the results

输出

[2019-11-04, 2019-12-02, 2020-01-06, 2020-02-03, 2020-03-02, 2020-04-06]

Ideone demo

答案 1 :(得分:3)

public List<LocalDate> filterDates(List<LocalDate> dates) {
    return dates.stream()
            .collect(Collectors.groupingBy(YearMonth::from))
            .values()
            .stream()
            .map(Collections::min) // .map(Collections::max)
            .collect(Collectors.toList());
}

您可以使用以下内容代替.map(Collections::min)

.map(list -> {
    list.sort(Comparator.naturalOrder());
    return list.get(0);
})

或者:

.map(list -> list.stream().max(Comparator.naturalOrder()))

答案 2 :(得分:3)

已经有很多好的答案。除了这些,我想补充:

  1. 请勿在原始列表中添加字符串。放置LocalDate个对象。如果您收到字符串输入,请先解析它,然后再添加到列表中。
  2. 您无需对内部列表进行排序即可获得其最小值(或最大值)。

在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会生成一个映射,但不是由列表收集映射值,而是由下游收集器生成。在这种情况下,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);
  

04/11 / 2019、02 / 12 / 2019、06 / 01 / 2020、03 / 02 / 2020、02 / 03 / 2020、06 / 04/2020

在Java 9中

no-arg Optional.orElseThrow是Java 10中引入的。在Java 8和9中,您可以使用例如:

            .map(old -> old.orElseThrow(() -> new IllegalStateException("This can’t happen")))

在Java 8中

List.of是Java 9中引入的。但是您说您已经有了列表,因此我考虑了如何在问题之外对其进行初始化。我相信读者可以根据需要找到在Java 8中对其进行初始化的方法。

答案 3 :(得分:1)

这是您需要做的一个顺序

  1. 将您的字符串解析为LocalDate
  2. 构建一个地图,其中您的钥匙将是一个月,而您的钥匙将是一个有序列表。
    1. 浏览所有列表并从每个列表中获取第一个值

这是您的算法。我将把实施留给您。

答案 4 :(得分:1)

// localDates是LocalDate的列表。您可以将其转换。

localDates.stream().forEach(localDate -> {
            Integer month = localDate.getMonthValue();
            if (localDateMap.containsKey(month)){
                if(localDate.isBefore(localDateMap.get(month))){
                    localDateMap.put(month,localDate);
                }
            }else{
                localDateMap.put(month,localDate);
            }
        });

然后从地图中获取所有值。