我想比较两个对象列表。我想要一个方法,它将返回列表的相等对象(交集)的集合。但是,这些列表中的对象类型使用 .equals() 以外的方法进行比较 (.isSimilar)。有没有一种简化和有效的方法来解决这个问题?
5 回答
内置方法都使用标准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
.
isSimilar()
您可以通过设置在项目类equals()
中调用isSimilar()
或使用扩展 List 实现之一的类来解决此问题,并且您应该覆盖contains()
要使用的方法isSimilar()
而不是equals().
请避免更改equals()
列表和项目的语义...
无论如何,我想你可能喜欢使用Guava 的函数式习语:
- 定义一个
Iterable<Pair<T,T>>
用一对 构造的实现类List<T>
,迭代从一对对应的元素到下一个。 - 创建一个用于
isSimilar()
第一对和第二对的对的谓词。 - 使用
Iterables.any(theIterableYouCreated, thePredicateYouCreated)
.
还没有结对课?见这里。此外,您需要处理不同长度的情况,这可以在构造迭代器之前完成;或者你可以用其他方式来做。
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.
没有解决方案。我认为您无法对列表进行排序(相似性)。因此,您需要将一个列表中的每个元素与所有其他元素进行比较,以查看是否没有找到相似的元素,以便拒绝它。N x M,二次复杂度。