簡體   English   中英

使用 Comparator 而不是 equals() 比較兩個 Java 集合

[英]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 以來添加到CollectionUtilsisEqualCollection方法。該方法使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM