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

因此箭头指示将被删除的列表对象。 我尝试了不同的方法:

  1. 使用流使用 sort(...).reverse 获取要从 insertDate 属性和 updateDate 属性中删除的最大值,然后比较这两个值以找到最大值并使用结果对象删除,但它太复杂并且有低性能
  2. 我尝试使用 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);
    }
}