按日期对项目进行分组

drJ*_*ava 10 java java-8 java-stream java-time

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

在此输入图像描述

我需要根据用户提供的"压缩"对它们进行分组.选项包括Day,Week,MonthYear.

如果用户选择day压缩,我需要将我的项目分组,以便在同一天创建的项目将被分组.在上面的示例中,仅在同一天创建了第1项和第2项.其他人也是团体,但他们只有一个项目,因为在他们的日子,只创建了一个项目.

{{item1, item2}, {item3}, {item4}, {item5}, {item6}, {item7}}
Run Code Online (Sandbox Code Playgroud)

如果用户选择week:

{{item1, item2, item3, item4}, {item5}, {item6}, {item7}}
Run Code Online (Sandbox Code Playgroud)

如果用户选择month:

{{item1, item2, item3, item4, item5}, {item6}, {item7}}
Run Code Online (Sandbox Code Playgroud)

如果用户选择year:

{{item1, item2, item3, item4, item5, item6}, {item7}}
Run Code Online (Sandbox Code Playgroud)

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

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

day=一年中的一天=一年中的
week一周=一年中的
month一个月
year=一年

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

Fed*_*ner 27

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

为此,首先创建以下内容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());
Run Code Online (Sandbox Code Playgroud)

注意:因为"day",TemporalAdjuster正在使用一个不受影响的日期.

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

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

LocalDate是由进行调整LocalDate.with(TemporalAdjuster)的方法.

  • 那实际上非常整洁 (2认同)

Man*_*dis 6

您可以使用 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()));
Run Code Online (Sandbox Code Playgroud)

groupingBycollect 的文档。在所有 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()));
Run Code Online (Sandbox Code Playgroud)

将 01/01/2017 与 01/10/2017 组合在一起,然后将 05/01/2017 与 05/04/2018 组合在一起