有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java使用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()

 }

现在我有了另一个processor类,我想在通过数据服务调用接收的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.
         */
    }
}

我的最终结果应该是一个类似集合的列表,其中包含重复的Tran对象,以便进一步更新

我在网上搜索,想知道如何使用Lambda API解决这个问题。 ->;尝试先将groupingBy与vDate一起使用,然后再与dDate一起使用,但之后我无法比较它们的pDate相等性

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

更新: 经过一些阅读,我试图在POJO类中通过over-riding 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;
    }

但它并没有像预期的那样工作。。。谁能帮帮我为什么


共 (2) 个答案

  1. # 1 楼答案

    听起来TranObject需要equalshashCode方法

    @Override
    public boolean equals(Object obj) {
      //check instanceof and self comparison
    
      TranObject other = (TranObject) obj;
    
    
      if(this.vDate.equals(other.vDate) && this.dDate.equals(other.dDate)) {
        //if pDate is not given then consider them duplicate
        if(this.pDate == null || other.pDate == null)
          return true;
    
        //if pDate are the same then they are duplicate, otherwise they are unique
        return this.pDate.equals(other.pDate);
      }
    
    return false;
    
    }
    
    //auto generated by Eclipse
    @Override
    public int hashCode() {
      final int prime = 31;
      int result = 1;
      result = prime * result + ((dDate == null) ? 0 : dDate.hashCode());
      result = prime * result + ((pDate == null) ? 0 : pDate.hashCode());
      result = prime * result + ((vDate == null) ? 0 : vDate.hashCode());
      return result;
    }
    
    

    现在,您有了一个equals方法来确定两个TranObjects是否被视为相等(基于您指定的规则),只需收集列表中多次出现的元素:

    private static List<TranObject> collectDuplicates(List<TranObject> list) {
      List<TranObject> result = new ArrayList<TranObject>();
    
      for(TranObject element : list) {
        if(Collections.frequency(list, element) > 1) 
          result.add(element);
      }
    
      return result;
    
    }
    
    

    这将返回所有具有重复项的元素

    注意:collectDuplicates不会返回重复元素的唯一列表。相反,它返回每个重复元素的列表(根据OP的问题)

  2. # 2 楼答案

    与您的需求最接近的是以嵌套的方式分组,然后过滤内部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();
    

    根据这些分组,值(来自map)合格的条件如下:

    1. 它们都有相同的pDate在这种情况下,innerMap将只有一个带有公共pDatem.size() == 1)的条目
    2. 分组后的一个值正好有一个pDate作为null(意思是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"字符串常量可以避免在收集带有null键或值的Map时出现故障(或不良做法)