![](/img/trans.png)
[英]Why is the comparator used instead of the equals() in Collections?
[英]Compare two Java Collections using Comparator instead of equals()
我有兩個要比較的相同類型對象的集合。 在這種情況下,我想根據不考慮對象的equals()
的屬性來比較它們。 在我的示例中,我正在使用名稱的排名集合,例如:
public class Name {
private String name;
private int weightedRank;
//getters & setters
@Override
public boolean equals(Object obj) {
return this.name.equals(obj.name); //Naive implementation just to show
//equals is based on the name field.
}
}
我想比較兩個集合以斷言,對於每個集合中的位置i
,該位置的每個 Name 的weightedRank
是相同的值。 我做了一些谷歌搜索,但沒有在 Commons Collections 或任何其他 API 中找到合適的方法,所以我想出了以下內容:
public <T> boolean comparatorEquals(Collection<T> col1, Collection<T> col2,
Comparator<T> c)
{
if (col1 == null)
return col2 == null;
if (col2 == null)
return false;
if (col1.size() != col2.size())
return false;
Iterator<T> i1 = col1.iterator(), i2 = col2.iterator();
while(i1.hasNext() && i2.hasNext()) {
if (c.compare(i1.next(), i2.next()) != 0) {
return false;
}
}
return true;
}
有沒有另一種方法可以做到這一點? 我是否錯過了 Commons Collections 中的一個明顯方法?
我也在 SO 上發現了這個問題,盡管在這種情況下我認為覆蓋equals()
更有意義。
在不久的將來(在撰寫本文時), Apache Commons Collections的發布中將包含與此非常相似的內容。 請參閱https://issues.apache.org/jira/browse/COLLECTIONS-446 。
您可以使用 Guava Equivalence類來分離“比較”和“等價”的概念。 您仍然需要編寫接受 Equivalence 子類而不是 Comparator 的比較方法(AFAIK Guava 沒有),但至少您的代碼不會那么混亂,並且您可以根據任何等價標准比較您的集合。
使用一組 equivance-wrapped 對象(參見Equivalence 中的wrap 方法)類似於 sharakan 提出的基於適配器的解決方案,但等價實現將與適配器實現分離,允許您輕松使用多個等價標准。
您可以使用自版本 4 以來添加到CollectionUtils
新isEqualCollection
方法。該方法使用Equator
接口實現提供的外部比較機制。 請檢查這個javadocs: CollectionUtils.isEqualCollection(...)和Equator 。
我不確定這種方式實際上更好,但它是“另一種方式”......
使用您原來的兩個集合,並為每個基礎對象創建包含一個 Adapter 的新集合。 Adapter 應該將.equals()
和.hashCode()
實現為基於Name.calculateWeightedRank()
。 然后你可以使用普通的 Collection 相等來比較 Adapters 的集合。
* 編輯 *
為Adapter
使用 Eclipse 的標准 hashCode/equals 生成。 您的代碼只會在您的每個基本集合上調用 adaptCollection,然后 List.equals() 兩個結果。
public class Adapter {
public List<Adapter> adaptCollection(List<Name> names) {
List<Adapter> adapters = new ArrayList<Adapter>(names.size());
for (Name name : names) {
adapters.add(new Adapter(name));
}
return adapters;
}
private final int name;
public Adapter(Name name) {
this.name = name.getWeightedResult();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + name;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Adapter other = (Adapter) obj;
if (name != other.name)
return false;
return true;
}
}
編輯:刪除舊答案。
您擁有的另一個選擇是創建一個名為Weighted
的界面,它可能如下所示:
public interface Weighted {
int getWeightedRank();
}
然后讓你的Name
類實現這個接口。 然后你可以改變你的方法看起來像這樣:
public <T extends Weighted> boolean weightedEquals(Collection<T> col1, Collection<T> col2)
{
if (col1 == null)
return col2 == null;
if (col2 == null)
return false;
if (col1.size() != col2.size())
return false;
Iterator<T> i1 = col1.iterator(), i2 = col2.iterator();
while(i1.hasNext() && i2.hasNext()) {
if (i1.next().getWeightedRank() != i2.next().getWeightedRank()) {
return false;
}
}
return true;
}
然后,當您發現需要加權和比較的其他類時,您可以將它們放入您的集合中,它們也可以相互比較。 只是一個想法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.