Java8 lambda 流删除对象的两个属性中具有最大值的对象
Java8 lambda stream remove objects with max in two attribute of objects
我有对象列表,任何对象都有两个日期属性 insertDate 和 updateDate 我需要找到在两个属性 insertDate 和 updateDate 之间具有绝对最大值的对象。
示例(列表的对象具有属性):
-> insertDate = 2020-10-11 15:48 updateDate = 2020-11-11 15:48
insertDate = null updateDate = 2019-09-11 15:48
insertDate = 2019-10-11 15:48 updateDate = null
insertDate = null updateDate = null
insertDate = 2019-10-11 15:48 updateDate = 2019-11-11 10:48
因此箭头指示将被删除的列表对象。
我尝试了不同的方法:
- 使用流使用 sort(...).reverse 获取要从 insertDate 属性和 updateDate 属性中删除的最大值,然后比较这两个值以找到最大值并使用结果对象删除,但它太复杂并且有低性能
- 我尝试使用 Collections 的 groupingBy...。但我找不到基于两个属性的最大值删除的模式
等等等
重要:考虑到我们搜索max的Date属性可以为null
有人可以提供性能和优雅的解决方案吗?
它太复杂了,我用 lambda 的速度不是很快....
非常感谢您的支持
List<Element> elements;
Comparator<Date> dateComparator = (Date a, Date b) -> a == b ? 0
: a == null ? -1 : b == null ? 1 : a.compareTo(b);
Optional<Element> maxElement = elements.stream().max((Element a, Element b) ->
dateComparator.compare(
dateComparator.compare(a.insertDate, a.updateDate) >= 0 ?
a.insertDate : a.updateDate,
dateComparator.compare(b.insertDate, b.updateDate) >= 0 ?
b.insertDate : b.updateDate));
这是一种可能。我这样做是使用 LocalDateTime, not Date because Date is outdated. The java::time 包应该被使用。出于演示目的,我更新了您的 class 版本。您需要将 class 的名称替换为 MyObject
才能使用您的数据。
数据。
List<MyObject> list = List.of(
new MyObject("2020-10-11 15:48", "2020-11-11 15:48"),
new MyObject(null, "2019-09-11 15:48"),
new MyObject("2019-10-11 15:48", null),
new MyObject(null, null),
new MyObject("2019-10-11 15:48", "2019-11-11 10:48"));
比较器。
- 这是通过获取每个对象日期对的持续时间,转换为毫秒,然后将每个对象作为长值进行比较来实现的。
Comparator<MyObject> comp = (a,b)->
Long.compare(Duration.between(a.getInsertDate(),a.getUpdateDate())
.toMillis(),
Duration.between(b.getInsertDate(),b.getUpdateDate())
.toMillis());
现在只需流式传输列表,随时过滤掉具有空值的对象。结果 returns 具有最长持续时间的对象。如果没有找到,它 returns 一个空值。
MyObject result = list.stream()
.filter(obj -> obj.getInsertDate() != null
&& obj.getUpdateDate() != null)
.max(comp).orElse(null);
System.out.println(result);
这会打印
2020-10-11 15:48 2020-11-11 15:48
为了完成,我提供了一个 Date
比较器供您使用,因为您的对象中有 Date
字段。只需将上一个流中的 dateComparator
替换为 comp
,它应该可以正常工作。
Comparator<MyObject> dateComparator = (a, b) -> Long.compare(
Math.abs(a.getInsertDate().toInstant().toEpochMilli()-
a.getUpdateDate().toInstant().toEpochMilli()),
Math.abs(b.getInsertDate().toInstant().toEpochMilli()-
b.getUpdateDate().toInstant().toEpochMilli()));
对象class定义。
class MyObject {
public LocalDateTime insertDate;
public LocalDateTime updateDate;
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
public MyObject(String insertDate, String updateDate) {
if (insertDate != null) {
this.insertDate = LocalDateTime.parse(insertDate,dtf);
}
if (updateDate != null) {
this.updateDate = LocalDateTime.parse(updateDate,dtf);
}
}
public LocalDateTime getInsertDate() {
return insertDate;
}
public LocalDateTime getUpdateDate() {
return updateDate;
}
public String toString() {
return insertDate.format(dtf) + " " + updateDate.format(dtf);
}
}
我有对象列表,任何对象都有两个日期属性 insertDate 和 updateDate 我需要找到在两个属性 insertDate 和 updateDate 之间具有绝对最大值的对象。 示例(列表的对象具有属性):
-> insertDate = 2020-10-11 15:48 updateDate = 2020-11-11 15:48
insertDate = null updateDate = 2019-09-11 15:48
insertDate = 2019-10-11 15:48 updateDate = null
insertDate = null updateDate = null
insertDate = 2019-10-11 15:48 updateDate = 2019-11-11 10:48
因此箭头指示将被删除的列表对象。 我尝试了不同的方法:
- 使用流使用 sort(...).reverse 获取要从 insertDate 属性和 updateDate 属性中删除的最大值,然后比较这两个值以找到最大值并使用结果对象删除,但它太复杂并且有低性能
- 我尝试使用 Collections 的 groupingBy...。但我找不到基于两个属性的最大值删除的模式
等等等
重要:考虑到我们搜索max的Date属性可以为null
有人可以提供性能和优雅的解决方案吗? 它太复杂了,我用 lambda 的速度不是很快....
非常感谢您的支持
List<Element> elements;
Comparator<Date> dateComparator = (Date a, Date b) -> a == b ? 0
: a == null ? -1 : b == null ? 1 : a.compareTo(b);
Optional<Element> maxElement = elements.stream().max((Element a, Element b) ->
dateComparator.compare(
dateComparator.compare(a.insertDate, a.updateDate) >= 0 ?
a.insertDate : a.updateDate,
dateComparator.compare(b.insertDate, b.updateDate) >= 0 ?
b.insertDate : b.updateDate));
这是一种可能。我这样做是使用 LocalDateTime, not Date because Date is outdated. The java::time 包应该被使用。出于演示目的,我更新了您的 class 版本。您需要将 class 的名称替换为 MyObject
才能使用您的数据。
数据。
List<MyObject> list = List.of(
new MyObject("2020-10-11 15:48", "2020-11-11 15:48"),
new MyObject(null, "2019-09-11 15:48"),
new MyObject("2019-10-11 15:48", null),
new MyObject(null, null),
new MyObject("2019-10-11 15:48", "2019-11-11 10:48"));
比较器。
- 这是通过获取每个对象日期对的持续时间,转换为毫秒,然后将每个对象作为长值进行比较来实现的。
Comparator<MyObject> comp = (a,b)->
Long.compare(Duration.between(a.getInsertDate(),a.getUpdateDate())
.toMillis(),
Duration.between(b.getInsertDate(),b.getUpdateDate())
.toMillis());
现在只需流式传输列表,随时过滤掉具有空值的对象。结果 returns 具有最长持续时间的对象。如果没有找到,它 returns 一个空值。
MyObject result = list.stream()
.filter(obj -> obj.getInsertDate() != null
&& obj.getUpdateDate() != null)
.max(comp).orElse(null);
System.out.println(result);
这会打印
2020-10-11 15:48 2020-11-11 15:48
为了完成,我提供了一个 Date
比较器供您使用,因为您的对象中有 Date
字段。只需将上一个流中的 dateComparator
替换为 comp
,它应该可以正常工作。
Comparator<MyObject> dateComparator = (a, b) -> Long.compare(
Math.abs(a.getInsertDate().toInstant().toEpochMilli()-
a.getUpdateDate().toInstant().toEpochMilli()),
Math.abs(b.getInsertDate().toInstant().toEpochMilli()-
b.getUpdateDate().toInstant().toEpochMilli()));
对象class定义。
class MyObject {
public LocalDateTime insertDate;
public LocalDateTime updateDate;
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
public MyObject(String insertDate, String updateDate) {
if (insertDate != null) {
this.insertDate = LocalDateTime.parse(insertDate,dtf);
}
if (updateDate != null) {
this.updateDate = LocalDateTime.parse(updateDate,dtf);
}
}
public LocalDateTime getInsertDate() {
return insertDate;
}
public LocalDateTime getUpdateDate() {
return updateDate;
}
public String toString() {
return insertDate.format(dtf) + " " + updateDate.format(dtf);
}
}