使用equals()的给定实现检查特定对象是否在列表中

时间:2013-11-19 18:44:09

标签: java list collections contains

我需要检查特定对象的等效实例是否在List中。

对象是具有等于太严格的等于方法的Final Class的实例。我希望能够为{contains}方法提供equals的不同实现,以检查对象是否包含在List中。

如果partsInBox的元素的顺序不同,则下面类中的equals方法将返回false;我需要将此行为更改为不加选择的顺序。

public final class Box {
    String category;
    List<Integer> partsInBox;

    @Override
    public boolean equals(Object o) {
        if (this == o) { return true; }
        if (o == null || getClass() != o.getClass()) { return false; }

        Box box = (Box) o;

        return category.equals(box.category) 
                && partsInBox.equals(box.partsInBox);
    }
}

我希望能够做到这样的事情:

List<Box> boxes; // list that I am checking
Box myBox; // what I am checking for

boolean contained = contatins(boxes, box, new EqualsMethod() {
    @Override
    public boolean areEqual(Box b1, Box b2) {
        if (b1 == b2) { return true; }

        return b1.category.equals(b2.category)
                && b1.partsInBox.containsAll(b2.partsInBox);
    }
});

我有哪些选择来实现此类功能?

6 个答案:

答案 0 :(得分:2)

理想的解决方案是改变equals()方法的当前行为。但是,如果您无权访问其他代码,则可能无法使用。

相反,您可以使用Apache CollectionUtils中的CollectionUtils.exists(collection, predicate)

http://commons.apache.org/proper/commons-collections/javadocs/api-3.2.1/org/apache/commons/collections/CollectionUtils.html

您可以使用自定义条件创建谓词,以确定对象是否足够

希望它有所帮助。

答案 1 :(得分:1)

因为课程是final所以你不能扩展它。

然而,您可以使用Comparator<T>接口,如下所示:

public class BoxComparator implements Comparator<Box> {
    @Override
    public int compare(Box b1, Box b2) {
        if (b1 == b2) { return 0; }

        // return -1 or 0 or +1...
    }

    public static void main(String[] args) {
        Box box1, box2;
        ...

        boolean contains = new BoxComparator().compare(box1, box2) == 0;
    }
}

如果您想将Box与另一个BoxList<Box>进行比较,我不能完全确定上面的代码示例 - 在后一种情况下,您无法导出{ {1}},但您可以执行类似的操作,例如Comparator

希望这有帮助。

答案 2 :(得分:1)

<强> Equator.java

public interface Equator<T> {
    boolean equals(T obj1, T obj2);
}

其他一些课程

public static <T> boolean contains(Collection<T> toSearch, T toSeek, Equator<T> equator) {
    for (T oneItem : toSearch) {
        if (equator.equals(oneItem, toSeek)) {
            return true;
        }
    }
    return false;
}

使用

import static some.other.class.contains; // The contains method from the class above

List<Box> boxes; // list that I am checking
Box myBox; // what I am checking for

boolean contained = contains(boxes, box, new Equator<Box>() {
    @Override
    public boolean equals(Box b1, Box b2) {
        if (b1 == b2) { return true; }

        return b1.category.equals(b2.category)
                && b1.partsInBox.containsAll(b2.partsInBox);
    }
});

答案 3 :(得分:0)

您可以使用具有Java内置方法的Comparator进行排序和二分查找。假设您有一个这样的类,其中a和b是您要用于排序的字段:

class Thing { String a, b, c, d; }

您可以定义比较器:

Comparator<Thing> comparator = new Comparator<Thing>() {
  public int compare(Thing o1, Thing o2) {
    if (o1.a.equals(o2.a)) {
      return o1.b.compareTo(o2.b);
    }
    return o1.a.compareTo(o2.a);
  }
};

然后对列表进行排序:

Collections.sort(list,comparator); 最后进行二分搜索:

int i = Collections.binarySearch(list, thingToFind, comparator);

答案 4 :(得分:0)

使用Closures在Groovy中会更容易(但不是那么显然效率低下)。好吧,我们进入Java:

package test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

// ------- Original code with comments added

public final class Box {

    // these should be final and List<Integer> should be immutable using
    // Collections.unmodifiableList() to avoid nasty surpises, and should 
    // possibly be pre-sorted

    String category;
    List<Integer> partsInBox;

    @Override
    public boolean equals(Object o) {
        // same instance, then true (works if null passed, too)
        if (this == o) {
            return true;
        }
        // Null and not exactly same class (instanceof not needed as "final"), then false
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Box box = (Box) o;
        // otherwise same category and exactly same list (including ordering)
        return category.equals(box.category) && partsInBox.equals(box.partsInBox);
    }
}

// ------- Create a wrapper class around Box, repainting the house

class WrappedBox {

    final Box box;     

    WrappedBox(Box box) {
        assert box != null;
        this.box = box;
    }

    public String getCategory() {
        return box.category;        
    }

    public List<Integer> getPartsInBox() {
        return box.partsInBox;        
    }

    public boolean equals(Object o) {
        // same instance, then true (works if null passed, too)
        if (this == o) {
            return true;
        }
        // Null and not same class, then false
        if (o == null || !(o instanceof WrappedBox)) {
            return false;
        }
        //
        // otherwise same category and the set of b1 parts is a superset of the set of b2 parts
        // this is not symmetric; should probably be a set comparison. What happens if there
        // are several integers with the same value??
        // return b1.category.equals(b2.category)
        //        && b1.partsInBox.containsAll(b2.partsInBox);
        //
        // SO RECODE AS AUXILIARY EXERCISE:
        //
        WrappedBox other = (WrappedBox)o;
        if (!this.getCategory().equals(other.getCategory())) {
            return false;
        }
        //
        // You probably want to buffer these somehow:
        //
        List<Integer> x1 = new ArrayList(this.getPartsInBox());
        List<Integer> x2 = new ArrayList(other.getPartsInBox());
        Collections.sort(x1);
        Collections.sort(x2);
        return x1.equals(x2); 
    }
}

// --------- Now we can ask for "contains", though one should really create a 
// ---------- List<WrappedBox> first if this happens often

class BoxHandler {

    static boolean containsBox(List<Box> boxes, Box box) {
        assert box != null;
        assert boxes != null;
        WrappedBox wbox = new WrappedBox(box);
        for (Box cur : boxes) {
            if (wbox.equals(new WrappedBox(cur))) {
                return true;
            }
        }
        return false;
    }
}

答案 5 :(得分:0)

您无法提供其他方法来与List进行比较。最好和最简单的解决方案是修改你的equals()方法。如果你不能修改equals,你可以实现一个Decorator类来创建一个包含你需要的areEquals比较的列表。

public class BoxList<E extends Box> implements List<E>{
    private List<E> list;

    public BoxList(List<E> list) {
        this.list = list;
    }

    //Modify the behavior of the methods
    @Override
    public boolean contains(Object o) {
        for(E element : list) {
            if (element.areEquals(o)) {
                return true;
            }
        }
        return false;
    }

    // Redirect all other List methods to the original list
    @Override
    public boolean add(E e) {
        return list.add(e);
    }
    @Override
    public void add(int index, E element) {
        list.add(index, element);        
    }
    ...