【问题标题】:removeAll method with different object types具有不同对象类型的 removeAll 方法
【发布时间】:2013-02-13 05:51:10
【问题描述】:

我有两个列表,我想对它们进行批量操作,例如使用方法 removeAll、retainAll、contains。问题是两个列表都有不同类型的对象,它们具有一个相同的字段。就像

class ObjectType1{
  Long field1;
  String field2;
  String field3
 }

class ObjectType2{
Long field1;
String field4;
Long field5

}

所以 list1 包含 ObjectType1 的元素,而 list2 包含 ObjectType2。我想根据 field1 进行批量操作,这在两种对象类型中都很常见。

我正在考虑基于公共字段在两个对象中实现 equals 方法。但是后来认为仅在一个字段上进行等于可能是错误的,因为将来可能需要在等于方法中添加基于其他字段的比较。请建议。

希望我的查询已经足够清楚了。请让我知道以进行澄清。

【问题讨论】:

  • 我猜你必须重写equals方法。

标签: java collections


【解决方案1】:

看看 Google 的 Guava 库。您可以使用Collections2.transform 来实现这一点。以下是retainAll() 的做法,例如:

import com.google.common.base.Function;
import com.google.common.collect.Collections2;
...
List<ObjectType1> list1 = ...;
List<ObjectType2> list2 = ...;
Colection<Long> list1field1 = 
  Collections2.transform(list1, 
                         new Function<ObjectType1, Long>() {
                           public Long apply(ObjectType1 input) {
                             return (null == input) ? null : input.field1;
                           }
                         });
Collection<Long> list2field1 = 
  Collections2.transform(list2, ...);

// list1.retainAll(list2) based on field1 equivalence
list1field1.retainAll(list2field1); // this affects the underlying list, ie list1.

【讨论】:

    【解决方案2】:

    试试下面的代码,它会给出常见值的列表

    package rais;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class ArrayClient {
    
        public static void main(String[] args) {
    
            List<ObjectType1> list1 = new ArrayList<ObjectType1>();
    
            ObjectType1 type1Obj1 = new ObjectType1(10001l, "XXX", "YYYY");
            list1.add(type1Obj1);
    
            ObjectType1 type1Obj2 = new ObjectType1(10002l, "XXX", "YYYY");
            list1.add(type1Obj2);
    
            ObjectType1 type1Obj3 = new ObjectType1(10003l, "XXX", "YYYY");
            list1.add(type1Obj3);
    
            ObjectType1 type1Obj4 = new ObjectType1(10004l, "XXX", "YYYY");
            list1.add(type1Obj4);
    
            ObjectType1 type1Obj5 = new ObjectType1(10005l, "XXX", "YYYY");
            list1.add(type1Obj5);
    
            List<ObjectType2> list2 = new ArrayList<ObjectType2>();
    
            ObjectType2 type2Obj1 = new ObjectType2(10001l, "XXX", 2000l);
            list2.add(type2Obj1);
    
            ObjectType2 type2Obj2 = new ObjectType2(10002l, "XXX", 2001l);
            list2.add(type2Obj2);
    
            ObjectType2 type2Obj3 = new ObjectType2(50002l, "XXX", 2002l);
            list2.add(type2Obj3);
    
            ObjectType2 type2Obj4 = new ObjectType2(50003l, "XXX", 2003l);
            list2.add(type2Obj4);
    
            List<ObjectType1> list3 = retainAll(list1, list2);
    
            for (ObjectType1 objectType : list3) {
                System.out.println(objectType);
            }
    
        }
    
        public static List<ObjectType1> retainAll(List<ObjectType1> firstList,  List<ObjectType2> secondList) {
    
            List<ObjectType1> list3 = new ArrayList<ObjectType1>();
    
            for (ObjectType1 first : firstList) {
                for (ObjectType2 second : secondList) {
                    if (first.getField1().equals(second.getField1())) {
                        list3.add(first);
                        break;
                    }
    
                }
    
            }
    
            return list3;
    
        }
    
    }
    

    在上面的程序下面两个对象

    ObjectType1 type1Obj1 = new ObjectType1(10001l, "XXX", "YYYY");
                list1.add(type1Obj1);
    
                ObjectType1 type1Obj2 = new ObjectType1(10002l, "XXX", "YYYY");
                list1.add(type1Obj2);
    

    在两个类中都有共同的 field1,list3 将只包含 type1 的两个元素。

    【讨论】:

      【解决方案3】:

      我用接口写过代码

      public interface IMatchable {
      
          Object getMatchingField();
      }
      

      然后我的 ObjectType1 和 ObjectType2 正在实现这个接口以及重写 equals 方法

      public class ObjectType1 implements IMatchable {
      
      @Override
      public Object getMatchingField() {
          return field1;
      }
       @Override
       public boolean equals(Object obj) {
          IMatchable matchableObj = null;
          if (obj instanceof IMatchable) {
              matchableObj = (IMatchable) obj;
          } else {
              return false;
          }
          return matchableObj.getMatchingField().equals(this.getMatchingField()) ? true: false;
      }
      }
      

      ObjectType2 与这些方法类似。

      【讨论】:

        【解决方案4】:

        如果我理解你的问题,你想要类似的东西

            class SuperObject{
                Long field1;
                public SuperObject(){}
                public void setField1(Long f){
                    field1 = f;
                }
                public Long getField1(){
                    return field1;
                }
                public boolean equals(Object obj){
            if(obj instanceof SuperObject)
                return field1.equals(((SuperObject) obj).getField1());
            else
                return false;
        }
            }
            class ObjectType1 extends SuperObject{
                String field2;
                String field3;
                ...    
        }
        
            class ObjectType2 extends SuperObject{
                String field4;
                Long field5;
                ...
            }
        

        列表应该是这样的

        List<SuperObject> list = new ArrayList<SuperObject>();
            ObjectType1 obj1 = new ObjectType1();
            ObjectType2 obj2 = new ObjectType2();
            list.add(obj1);
            list.add(obj2);
        

        列表中的对象现在具有相同的相等方法实现,基于超类中的field1

        【讨论】:

          【解决方案5】:

          正如@Dilum 所写,您可以使用 Google 的 Guava 库。
          此外,如果您只有列表,则应改用 Lists.transform
          此外,如果您使用 Java 8,那么它看起来像:

          List<Long> list1field1 =
              Lists.transform(list1, input -> input == null ? null : input.field1);
          

          或者您可以手动操作:

          // list1.removeAll(list2);
          Set<Long> set = new HashSet<Long>();
          for (ObjectType2 o2 : list2) {
              set.add(o2.field1);
          }
          Iterator<ObjectType1> i = list1.iterator();
          while (i.hasNext()) {
              if (set.contains(i.next().field1)) {
                  i.remove();
              }
          }
          

          【讨论】:

            猜你喜欢
            • 2015-11-09
            • 2013-08-14
            • 2019-12-02
            • 2015-06-22
            • 1970-01-01
            • 1970-01-01
            • 2013-08-13
            • 1970-01-01
            • 2021-10-16
            相关资源
            最近更新 更多