使用java流API对日期进行排序、分组和计数
如何使用流API解决以下示例使用java流API对日期进行排序、分组和计数,java,java-stream,Java,Java Stream,如何使用流API解决以下示例 /* * Calculate the total number of Mondays for the specified years grouped by month */ EnumMap<Month, Long> totalMondaysByMonth(int yearSince, int yearUntilInclusive); /* * Issue a list of Fridays on the 13th for the specifie
/*
* Calculate the total number of Mondays for the specified years grouped by month
*/
EnumMap<Month, Long> totalMondaysByMonth(int yearSince, int yearUntilInclusive);
/*
* Issue a list of Fridays on the 13th for the specified years,
* sorted in ascending order first by year, and second by name of the month
*/
List<LocalDate> friday13s(int yearFrom, int yearUntilInclusive);
/*
*计算按月份分组的指定年份的星期一总数
*/
EnumMap totalMondaysByMonth(整数年自,整数年至结束);
/*
*在指定年份的13日发布一份星期五清单,
*按升序排序,第一个按年份排序,第二个按月份名称排序
*/
列出13号星期五(国际年开始,国际年结束);
我的示例解决方案:
public EnumMap<Month, Long> totalMondaysByMonth(int yearSince, int yearUntilInclusive) {
return Stream.iterate(LocalDate.of(yearSince, 0, 0), date -> date.plusYears(1))
.limit(yearUntilInclusive)
.filter(x -> x.getDayOfWeek() == DayOfWeek.MONDAY)
.collect(Collectors.groupingBy(LocalDate::getMonth, Collectors.summingLong(???));
}
public EnumMap totalMondaysByMonth(int yearbegin,int yearuntinclusive){
return Stream.iterate(LocalDate.of(yearbeash,0,0),date->date.plusYears(1))
.限额(截止到最后一年)
.filter(x->x.getDayOfWeek()==DayOfWeek.MONDAY)
.collect(Collectors.groupingBy(LocalDate::getMonth,Collectors.summingLong(?));
}
我应该在(Collectors.summingLong(???))中插入什么代码来计算星期一的数量
public List<LocalDate> friday13s(int yearFrom, int yearUntilInclusive) {
return Stream.iterate(LocalDate.of(yearFrom, 0, 0), date -> date.plusYears(1))
.limit(yearUntilInclusive)
.filter(x -> x.getDayOfWeek() == DayOfWeek.FRIDAY || x.getDayOfMonth() == 13)
.sorted(Comparator.comparing(LocalDate::getYear).thenComparing(LocalDate::getMonth))
.collect(Collectors.toList());
}
公共列表星期五13s(int yearFrom,int yearuntinclusive){
返回Stream.iterate(LocalDate.of(yearFrom,0,0),date->date.plusYears(1))
.限额(截止到最后一年)
.filter(x->x.getDayOfWeek()==DayOfWeek.FRIDAY | | x.getDayOfMonth()==13)
.sorted(Comparator.comparing(LocalDate::getYear)。然后比较(LocalDate::getMonth))
.collect(Collectors.toList());
}
告诉我如何正确书写。我只会帮助您修复第一个,您可以理解这一点,也可以修复第二个(几乎相同) 你首先说:
Stream.iterate(LocalDate.of(yearSince, 0, 0), date -> date.plusYears(1))
但是你真的需要在这里重复几年吗?你需要找出周一
(哪几天是天,不是?)这是这里的主要问题,因为你的“循环”只会发生与年差相同的次数。假设你想要2018-2020年的时间间隔-你打算用你现在拥有的迭代多少次
但是现在您需要考虑何时“停止”这个循环,这就是为什么要使用limit
:
.limit(yearUntilInclusive)
问题是,如果你想正确地迭代天
,你真的不知道什么时候停止,是吗?理想情况下,您希望通过使用谓词来停止,例如:我希望从2018的第一天开始,到2020的最后一天停止<代码>限制
不能真正做到这一点(你可以通过从上次的到第一次的之间的天数差来实现-我会让你知道怎么做)。或者,我发现将谓词
与takeWhile
一起使用更容易(至少需要java-9)
然后,可以将收集器.summingLong
设置为收集器.summingit
(从32
位整数跳到64位长度需要很多年)。你需要在那里做什么?对于每一天,你有一个匹配,只需添加一个。简单的“添加一个”也称为counting
,并且有一个用于该收集器的收集器。counting()
也可以使用
最后一点是EnumMap
可以将Map
作为其构造函数的参数;因此:
public static EnumMap<Month, Integer> totalMondaysByMonth(int yearSince, int yearUntilInclusive) {
return Stream.iterate(LocalDate.of(yearSince, 1, 1), date -> date.plusDays(1))
.takeWhile(date -> date.getYear() <= yearUntilInclusive)
.filter(x -> x.getDayOfWeek() == DayOfWeek.MONDAY)
.collect(
Collectors.collectingAndThen(
Collectors.groupingBy(LocalDate::getMonth, Collectors.summingInt(x -> 1)),
EnumMap::new
)
);
}
public static EnumMap totalMondaysByMonth(int yearbegin,int yearuntinclusive){
return Stream.iterate(LocalDate.of(yearbefore,1,1),date->date.plusDays(1))
.takeWhile(date->date.getYear()x.getDayOfWeek()==星期一)
.收集(
收藏,收藏,然后(
Collectors.groupby(LocalDate::getMonth,Collectors.summingit(x->1)),
EnumMap::新建
)
);
}
但你能在这里更有效吗?您可以找到一年中的第一个星期一,然后从该星期一开始迭代几周,而不是几天:
LocalDate firstMonday = LocalDate.of(yearSince, 1, 1).with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY));
EnumMap<Month, Integer> right =
Stream.iterate(firstMonday, date -> date.plusWeeks(1))
.takeWhile(date -> date.getYear() <= yearUntilInclusive)
.collect(
Collectors.collectingAndThen(
Collectors.groupingBy(LocalDate::getMonth, Collectors.summingInt(x -> 1)),
EnumMap::new
)
);
localdatefirstmonday=LocalDate.of(yearbefore,1,1).with(temporaladjusts.firstInMonth(DayOfWeek.MONDAY));
枚举映射权=
Stream.iterate(第一个星期一,date->date.plusWeeks(1))
.takeWhile(日期->日期.getYear()1)),
EnumMap::新建
)
);
欢迎来到SO。你的第一句和最后一句不匹配。你的问题到底是什么?请你重新措辞好吗?谢谢,你解释得很好。我想我可以自己完成第二个任务并结束这个主题。当你在做Stream.iterate时,.filter(x->x.getDayOfWeek()==DayOfWeek.MONDAY)
还是必需的(firstMonday,date->date.plusWeeks(1))
?请注意,Stream.iterate(a,b).takeWhile(c)
可以替换为Stream.iterate(a,c,b)
…和Collectors.collectionandthen(Collectors.groupingBy(LocalDate::getMonth,Collectors.summingit(x->1)),EnumMap::new)
不仅承担了不必要的复制操作,而且在结果映射为空时可能会失败。所以最好使用Collectors.groupingBy(LocalDate::getMonth,()->新的EnumMap(Month.class),Collectors.summingit(x->1))
。由于这需要Java 9,因此使用收集器.summingit(x->1)
而不是计数()
没有任何优势。OP的原始代码已经有一个EnumMap
返回类型。@Holger确实可以替换该过滤器。我也同意流。iterate(a,b,c)
-我想了想,但听起来已经有太多的建议了。不过,这个EnumMap
建议非常像!更惯用,甚至更高效:EnumMap right=firstMonday.datesUntil(firstMonday.withYear(yearuntinclusive+1),Period.ofWeeks(1)).collect(collector.groupingBy(LocalDate::getMonth,()->new EnumMap(Month.class),Collectors.counting())代码>