4

我想比较两个对象列表。我想要一个方法,它将返回列表的相等对象(交集)的集合。但是,这些列表中的对象类型使用 .equals() 以外的方法进行比较 (.isSimilar)。有没有一种简化和有效的方法来解决这个问题?

4

5 回答 5

4

内置方法都使用标准equals方法来查看两个对象是否相等;没有人会使用您的自定义isSimilar方法。

幸运的是,自己编写计算交集的逻辑很容易:遍历第一个列表中的元素,如果它存在于第二个列表中,则将其添加到交集。

List<YourObject> intersection = new ArrayList<YourObject>();
for (YourObject a: list1) for (YourObject b: list2) {
    if (a.isSimilarTo(b)) {
        intersection.add(a);
        break;
    }
}

计算复杂度:如果第一个列表有 n 个项目,第二个列表有 m 个项目,则此算法可能会进行 O(nm) 比较。如果列表被排序或者如果可以使用不同的数据结构(例如哈希表),则复杂性可以降低到 O(n+m)。

另一方面,您可以为您的对象创建一个包装类,并使用 isSimilar 方法来实现相等:

final class YourObjectWrapper {
    YourObject value;
    public boolean equals(Object o) {
        return o instanceof YourObjectWrapper
                   ? value.isSimilarTo(((YourObjectWrapper) o).value) 
                   : false;
    }
    // don't forget to override hashCode
}

如果您使用这些包装器对象填充列表,则可以使用内置方法,例如retainAll.

于 2013-09-20T22:17:50.910 回答
1

isSimilar()您可以通过设置在项目类equals()中调用isSimilar()或使用扩展 List 实现之一的类来解决此问题,并且您应该覆盖contains()要使用的方法isSimilar()而不是equals().

于 2013-09-20T22:40:19.377 回答
1

请避免更改equals()列表和项目的语义...

无论如何,我想你可能喜欢使用Guava 的函数式习语

  • 定义一个Iterable<Pair<T,T>>用一对 构造的实现类List<T>,迭代从一对对应的元素到下一个。
  • 创建一个用于isSimilar()第一对和第二对的对的谓词。
  • 使用Iterables.any(theIterableYouCreated, thePredicateYouCreated).

还没有结对课?见这里。此外,您需要处理不同长度的情况,这可以在构造迭代器之前完成;或者你可以用其他方式来做。

于 2013-09-21T20:39:05.567 回答
0

The efficient streamlined way to do this is to write you own method for this. That said, this would be a simple method, where you compare the two objects and if they are equal you add them to a list, or other collection.

于 2013-09-20T22:11:56.417 回答
0

没有解决方案。我认为您无法对列表进行排序(相似性)。因此,您需要将一个列表中的每个元素与所有其他元素进行比较,以查看是否没有找到相似的元素,以便拒绝它。N x M,二次复杂度。

于 2013-09-20T22:17:38.830 回答