首页 > 解决方案 > 使用 Lambda API 比较 ArrayList 的多个字段并收集对象

问题描述

我在我的项目中面临类似于下面描述的情况,其中我无法实现代码。

我有一个 POJO 类

    public class TranObject {

        public String loadId;
        public String vDate;
        public String dDate;
        public String pDate;

        public TranObject(String loadId, String vDate, String dDate, String pDate) {
            super();
            this.loadId = loadId;
            this.vDate = vDate;
            this.dDate = dDate;
            this.pDate = pDate;
        }
      //Getter and Setters
      //toString()

 }

现在我有另一个处理器类,我想在我通过数据服务调用接收的 tranload 对象之间实现一些比较,并将它们收集到另一个集合中。 实现逻辑在下面的评论中给出。请阅读以下评论

import java.util.Arrays;
import java.util.List;

public class DemoClass {

    public static void main(String[] args) {
        List<TranObject> listObj = Arrays.asList(
                new TranObject("LOAD1", "20180102", "20180202", null),
                new TranObject("LOAD2", "20180402", "20180403", null),
                new TranObject("LOAD3", "20180102", "20180202", "20190302"),
                new TranObject("LOAD4", "20180402", "20180403", null),
                new TranObject("LOAD5", "20200202", "20200203", null)
        );

        /*
        IF (obj1, obj3 vdate and dDate are equal)
                IF(pDate == null for obj1 or obj3)
                    THEN obj1 and obj3 are equal/duplicates, and we collect them.
                ELSE IF(pDate != null for obj1 and obj3)
                    IF(pDate is same for obj1 and obj3)
                        THEN obj1 and obj3 are duplicates, and we collect them.
                    ELSE
                        THEN obj1 and obj3 are unique.
         */
    }
}

我的最终结果应该是一个像 List 这样的集合,其中包含重复的 Tran 对象以供进一步更新。

我搜索了互联网以了解如何使用 Lambda API 解决它。-> 尝试先使用 groupingBy 和 vDate,然后使用 dDate,但后来我无法比较它们的 pDate 是否相等。

谁能帮我解决这个问题。一点帮助对我很有帮助。我被困在这里

更新: 经过一番阅读,我试图通过覆盖 POJO 类中的 equals 方法来实现相同的功能,如下所示:

@Override
    public boolean equals(Object obj) {
        boolean isEqual=false;
        if(obj!=null) {
            TranObject tran = (TranObject) obj;
            isEqual=(this.vDate.equals(tran.getvDate()) && this.dDate.equals(tran.getdDate()));
            if(isEqual && this.pDate != null && tran.getpDate()!= null) {
                isEqual = (this.pDate.equals(tran.getpDate()));
            }
        }
        return isEqual;
    }

仍然没有按预期工作......有人可以帮我解释为什么吗?

标签: javalambdacollectionsjava-8grouping

解决方案


最接近您的要求将以嵌套方式分组,然后过滤内部以适应Map各种条件,同时最终只对值感兴趣。

Stream<Map<String, List<TranObject>>> groupedNestedStream = listObj.stream()
        .collect(Collectors.groupingBy(a -> Arrays.asList(a.vDate, a.dDate)
                , Collectors.groupingBy(t -> t.pDate == null ? "default" : t.pDate)))
        .values().stream();

从这些分组中,值(来自地图)符合条件的条件是

  1. 在这种情况下,它们都相同pDate,innerMap 将只有一个带有 common pDate ( m.size() == 1)的条目
  2. 分组后的值之一恰好pDatenull (含义m.containsKey("default") && m.get("default").size() == 1
List<TranObject> tranObjects = groupedNestedStream
        .filter(m -> m.size() == 1 || (m.containsKey("default") && m.get("default").size() == 1))
        .flatMap(m -> m.values().stream().flatMap(List::stream))
        .collect(Collectors.toList());

请注意,使用"default"字符串常量来避免在收集Map带有null键或值的 a 时失败(或不良做法)。


推荐阅读