按日期对项目进行分组

2022-09-02 14:24:01

我的列表中有项目,这些项目有一个字段,显示项目的创建日期。

enter image description here

我需要根据用户给出的“压缩”对它们进行分组。选项包括 、 和 。DayWeekMonthYear

如果用户选择压缩,我需要对项目进行分组,以便对在同一天创建的项目进行分组。在上面的示例中,在同一天仅创建项目 1 和项目 2。其他的也是组,但它们将只有一个项目,因为在他们的一天,只创建了一个项目。day

{{item1, item2}, {item3}, {item4}, {item5}, {item6}, {item7}}

如果用户选择 :week

{{item1, item2, item3, item4}, {item5}, {item6}, {item7}}

如果用户选择 :month

{{item1, item2, item3, item4, item5}, {item6}, {item7}}

如果用户选择 :year

{{item1, item2, item3, item4, item5, item6}, {item7}}

创建组后,项目的日期并不重要。我的意思是,只要创建了组,密钥可以是任何东西。

在使用的情况下,我认为作为键如下:Map

day= 一年
中的某一天 = 一年
中的周 = 一年
中的月份 = 年份weekmonthyear

这个问题的最佳解决方案是什么?我甚至无法启动它,除了迭代之外,我想不出其他解决方案。


答案 1

我会在分类器上使用调整后的内容,以便将具有相似日期的项目(根据用户给出的压缩)分组在一起。Collectors.groupingByLocalDate

为此,请首先创建以下内容:Map

static final Map<String, TemporalAdjuster> ADJUSTERS = new HashMap<>();

ADJUSTERS.put("day", TemporalAdjusters.ofDateAdjuster(d -> d)); // identity
ADJUSTERS.put("week", TemporalAdjusters.previousOrSame(DayOfWeek.of(1)));
ADJUSTERS.put("month", TemporalAdjusters.firstDayOfMonth());
ADJUSTERS.put("year", TemporalAdjusters.firstDayOfYear());

注意:对于 ,a 正在使用允许未触及的日期。"day"TemporalAdjuster

接下来,使用用户给定的 动态选择如何对项目列表进行分组:compression

Map<LocalDate, List<Item>> result = list.stream()
    .collect(Collectors.groupingBy(item -> item.getCreationDate()
            .with(ADJUSTERS.get(compression))));

通过 LocalDate.with(TemporalAdjuster) 方法进行调整。LocalDate


答案 2

你可以得到你用java 8流描述的行为:

Map<LocalDate, List<Data>> byYear = data.stream()
        .collect(groupingBy(d -> d.getDate().withMonth(1).withDayOfMonth(1)));
Map<LocalDate, List<Data>> byMonth = data.stream()
        .collect(groupingBy(d -> d.getDate().withDayOfMonth(1)));
Map<LocalDate, List<Data>> byWeek = data.stream()
        .collect(groupingBy(d -> d.getDate().with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY))));
Map<LocalDate, List<Data>> byDay = data.stream()
        .collect(groupingBy(d -> d.getDate()));

用于分组的文档收集。在所有 4 种情况下,LocalDate 都用作键。为了适当地分组,对其进行了修改,以便所有日期都具有相同的月份和日期或相同的日期,但不同的月份或相同的月份和星期中的同一天(星期一),这会导致明显的分组规则。数据中的日期不仅修改密钥。这将考虑当年份相同时月份是相同的,当完整日期相同时,日期是相同的。

例如,按月份分组时,这些日期将具有相同的键:

01/01/2017 -->键 01/01/2017
04/01/2017 -->键 01/01/2017
05/01/2017 -->键 01/01/2017

并且按周分组时,这些日期将具有相同的键(日期是上一个星期一):

04/01/2017 -->键 02/01/2017
05/01/2017 -->键 02/01/2017

您可能希望改为按月份中的同一天分组,例如,无论年份和月份如何。你会像这样实现它:

Map<Integer, List<Data>> byDayOfMonth = data.stream()
        .collect(groupingBy(d -> d.getDate().getDayOfMonth()));

这将把01/01/2017与01/10/2017和05/01/2017与05/04/2018组合在一起


推荐