我有以下代码:
list.sort(Comparator
.comparing(ProgrammData::getEnd)
.thenComparing(ProgrammData::getStart).reversed());
我的问题是我想让我的列表按多个东西排序:1.)将它们分组为未来事件和过去事件(通过检查System.currentMilliseconds()是否大于结束时间戳)2.)按开始升序对未来事件排序3.)按结束降序对过去事件排序
我可以用Java 8 Lambda来做这个吗?或者我需要另一种排序项目的方法吗?
示例:
events could look like this:
name, start, end
event1, 2022-02-220100, 2022-02-220300
event2, 2022-02-220200, 2022-02-241800
event3, 2022-02-251200, 2022-02-281500
event4, 2022-02-261600, 2022-02-262100
if now() is 2022-02-221200 So the order should be:
event3 (next item in the future)
event4 (2nd next item in the future)
event2 (Ended closer to now than event1)
event1 (Longest in the past)
6条答案
按热度按时间kh212irz1#
正如我所理解的这个问题,你依赖于一个 * 现有的API*,它期望一个事件列表,并希望它们作为一个单个列表一起处理,并根据它们的 * 开始 * 和 * 结束 * 日期-时间进行排序。这是可以实现的。
我假设存储在
ProgrammData
对象中的与时间相关的事件数据的类型是String
。如果不是这样,并且这些字段是例如遗留类型Date
,那么只需要做一些小的更改。我的想法是将所有功能封装在
TwoWaySorting
中,这样所有的实现细节都被抽象掉了。在客户端代码中,只需要TwoWaySorting.getSorted(programmData)
这一行就可以生成一个事件的排序列表。由于
TwoWaySorting
类的责任与状态无关,因此它的所有行为都用 static 修饰符标记,其构造函数为 private。它有一个嵌套的静态类Element
,它是ProgrammData
顶部的 Package 器(如果我假设ProgrammData
是现有IPA的一部分是正确的,那么它必须按原样使用而不做任何更改)。 Package 后的ProgrammData
对象的相关数据以方便的形式进行排序。下面是
getSorted()
方法的简要概述:Element
类的示例 * Package * 每个事件;为了 Package 事件,静态方法
LocalDateTime.parse()
接受CharSequence
和适当的formatter用于解析基于字符串的时间相关数据。TwoWaySorting
类的核心是getComparator()
方法返回的comparator,让我们仔细研究一下。它的第一部分负责根据
currentTime
将元素分为两组:顾名思义,
LocalDateTime
类的示例方法isBefore()
返回true如果 * 此日期-时间 * 对象在作为参数传递的 * 日期-时间对象 * 之前。根据
boolean
值的自然排序顺序,false在true之前。因此,对于在未来结束的invent,isBefore()
将产生false,这意味着它将出现在排序列表的 * 开头 *。返回:一个字典顺序比较器,由this和long sort key组成
方法
thenComparingLong()
(* 上面显示了javadoc的引用 *)返回一个聚合比较器,它由之前获得的 comparator(分离 * 过去 * 和 * 未来 * 事件)和一个 comparator 组成,该 *comparator * 基于作为参数提供的ToLongFunction
,它相应地将元素与该 * 函数 * 提取的long
值进行比较。方法
toEpochSecond()
从日期时间对象中提取 epoch 的 * 秒数 * 作为long
。ZoneOffset
是toEpochSecond()
作为参数所期望的,在这种情况下,对结果没有影响,格林威治的偏移量可以用任何其他有效偏移量替换。*由于 future 事件必须按升序排序
toEpochSecond()
产生的值按原样使用,对于 past 事件必须按降序排序它乘以-1
以反转比较结果。注:
<Element,Boolean>comparing()
。如果没有显式声明,编译器没有足够的数据来确定变量element
的类型,在comparing()
和thenComparingLong()
中,其类型将被推断为**Object
。如果我们只使用这些静态方法中的类型编译器将根据getComparator()
方法的 * 返回类型 * 正确推断为Element
。但对于我们的情况,我们需要显式提供此信息。for information on the syntax of generic methods, take a look at this tutorial
TwoWaySorting
class这个解决方案是为了 * 干净 * 和 * 可重用 *。所以在
main()
中,除了 source list 之外,只有一行代码可以获得一个排序的列表并将其打印在控制台上。注意:
getSorted()
不会导致源的突变,而是创建一个新的列表。输出(与提供的示例相同)
pkwftd7m2#
试试这个:
yr9zkbsy3#
有很多事情需要注意。首先,一个是
.thenComparing(...)
方法,它只在前面的比较结果相等时才会发生。你可以在文档中阅读更多关于它的行为。第二,如果我是你的话,如果我可以用一个简单的比较器来解决这个问题,我就不会过多地使用流。假设你正在寻找
ProgrammData
列表的一个新示例,我以流的风格编写了我的代码,但是Comparator可以与List
的sort
方法一起使用。如果没有更精确的给定时钟,LocalDateTime().now()在内部使用System.currentTimeMillis()。
xt0899hw4#
你需要把过去和未来的事件分别放在不同的列表中,并进行相应的排序,最后一步是把两个列表连接起来。
结果是这样的:
gkl3eglg5#
你的例子看起来不正确-event 2是在未来,应该与3和4一起排序。无论如何,你应该把列表分成2,未来和过去的事件,并相应地排序。你可以用流来做,或者把列表分成两部分,选择你喜欢的。
对于设置:
1.选项1 -流
首先,我们将列表流式传输并收集到
Map<Boolean, Set<ProgrammData>>
中,true key将收集过去的事件,false - future。然后流式Map条目,按键排序以确保未来的事件- false key,在过去之前,并获得值(集合)。因为值在TreeSet
中具有相应的比较器,所以它们已经排序。1.选项2 -将列表拆分为2,对每个列表进行排序,再次收集到单个列表中
基本上,创建两个新列表,一个用于将来,另一个用于过去,对每个列表进行排序,将它们添加到新列表中。或者您可以将它们保存在初始列表中。
这两个选项的结果都是按顺序的-事件2、3、4(未来,按开始升序排序),事件5、1(过去,按结束降序排序)。
rqdpfwrv6#
你的例子很混乱。正如你在标题中所说的,
event2
应该被处理为好像它在将来,由于它的结束时间(2022-02-241800
)在现在之后(2022-02-221200
),所以有序元素应该是如果这是正确的,您可以尝试以下操作:
鉴于