问题描述
我的过程对象列表如下
Procedure1 01/01/2020
Procedure2 03/01/2020
Procedure3 03/01/2020
Procedure1 04/01/2020
Procedure5 05/01/2020, 02/01/2020
Procedure2 06/01/2020
我的Procedure类就像
and my Procedure class is like
Class Procedure {
List<Date> procedureDate;
String procedureName;
}
我要根据以下条件对对象进行分类和分组.
I want to sort and group the objects based on the below conditions.
- 所有过程均应根据过程名称进行分组.
- 程序必须按程序日期的降序排列. [日期列表中的第一个元素,即
procedureDate.get[0]]
- 归类在一起的相同过程应按日期降序排列.
最终结果必须是
Procedure2 06/01/2020
Procedure2 03/01/2020
Procedure5 05/01/2020, 02/01/2020
Procedure1 04/01/2020
Procedure1 01/01/2020
Procedure3 03/01/2020
我能够使用Comparator和旧的Java代码来实现这一目标.使用java8流,收集器和分组依据是否可以实现相同的目的?
I was able to achieve this using Comparator and old java code. Is it possible to achieve the same using java8 streams, collectors and grouping by?
推荐答案
这是一个非常有趣的问题.解决方案不像看起来那么简单.您必须将解决方案分为多个步骤:
This is a very interesting question. The solution is not as easy as it looks to be. You have to divide the solution into multiple steps:
- 基于
List<Date>
中的第一个日期获取每个分组的procedureName
的最大值. - 根据第一步中创建的
Map<String, Date
的最大Date
值比较Procedure
实例. - 如果它们相等,则用名称区分它们(例如两次
Procedure 2
). - 如果它们仍然相等,请根据它们的实际第一个日期对
Procedure
实例进行排序.
- Get the max value for each grouped
procedureName
based on the first dates in theList<Date>
. - Compare the
Procedure
instances based on maxDate
value from theMap<String, Date
created in the step one. - If they are equal distinguish them by the name (ex. two times
Procedure 2
). - If they are still equal, sort the
Procedure
instances based on their actual first date.
这里是演示: https://www.jdoodle.com/iembed/v0 /Te .
第1步
List<Procedure> procedures = ...
Map<String, Date> map = procedures.stream().collect(
Collectors.collectingAndThen(
Collectors.groupingBy(
Procedure::getProcedureName,
Collectors.maxBy(Comparator.comparing(s -> s.getProcedureDate().get(0)))),
s -> s.entrySet().stream()
.filter(e -> e.getValue().isPresent())
.collect(Collectors.toMap(
Map.Entry::getKey,
e -> e.getValue().get().getProcedureDate().get(0)))));
..解释:有一种简单的方法来获取具有procedureName
分组的最大首个日期的Procedure
.
.. explained: There is a simple way to get a Procedure
with maximum first date grouped by procedureName
.
Map<String, Optional<Procedure>> mapOfOptionalProcedures = procedures.stream()
.collect(Collectors.groupingBy(
Procedure::getProcedureName,
Collectors.maxBy(Comparator.comparing(o -> o.getProcedureDate().get(0)))));
但是,返回的结构有点笨拙(Map<String, Optional<Procedure>>
),要使其有用并直接返回Date
,就需要附加的下游收集器Collectors::collectingAndThen
,该收集器使用Function
作为结果映射器:
However, the returned structure is a bit clumsy (Map<String, Optional<Procedure>>
), to make it useful and return Date
directly, there is a need of additional downstream collector Collectors::collectingAndThen
which uses a Function
as a result mapper:
Map<String, Date> map = procedures.stream().collect(
Collectors.collectingAndThen(
/* grouping part */,
s -> s.entrySet().stream()
.filter(e -> e.getValue().isPresent())
.collect(Collectors.toMap(
Map.Entry::getKey,
e -> e.getValue().get().getProcedureDate().get(0)))));
...实际上是第一个片段.
... which is effectively the first snippet.
第2步,第3步和第4步
基本上,按每个组的最大日期排序.然后按名称排序,最后按实际的第一个日期排序.
Basically, sort by the maximum date for each group. Then sort by the name and finally by the actual first date.
Collections.sort(
procedures,
(l, r) -> {
int dates = map.get(r.getProcedureName()).compareTo(map.get(l.getProcedureName()));
if (dates == 0) {
int names = l.getProcedureName().compareTo(r.getProcedureName());
if (names == 0) {
return r.getProcedureDate().get(0).compareTo(l.getProcedureDate().get(0));
} else return names;
} else return dates;
}
);
排序结果
根据您的问题使用不推荐使用的java.util.Date
,排序后的procedures
将对项目进行排序,例如您的预期代码段(我已经覆盖了Procedure::toString
方法)
Using the deprecated java.util.Date
according to your question, the sorted procedures
will have sorted items like your expected snippet (I have overrided the Procedure::toString
method)
@Override
public String toString() {
return procedureName + " " + procedureDate;
}
Procedure2 [Mon Jan 06 00:00:00 CET 2020]
Procedure2 [Fri Jan 03 00:00:00 CET 2020]
Procedure5 [Sun Jan 05 00:00:00 CET 2020, Thu Jan 02 00:00:00 CET 2020]
Procedure1 [Sat Jan 04 00:00:00 CET 2020]
Procedure1 [Wed Jan 01 00:00:00 CET 2020]
Procedure3 [Fri Jan 03 00:00:00 CET 2020]
这篇关于对对象列表进行排序和分组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!