18

問題文

比較したい同じタイプのオブジェクトのコレクションが2つあります。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.
    }
}

2つのコレクションを比較して、i各コレクションの位置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;
}

質問

これを行う別の方法はありますか?CommonsCollectionsからの明らかな方法を見逃しましたか?

関連している

私もSOでこの質問を見つけましたが、その場合はオーバーライドequals()する方が少し理にかなっていると思います。

編集

これに非常によく似たものが、近い将来(この記事の執筆時点で)、ApacheCommonsCollectionsのリリースに入る予定です。https://issues.apache.org/jira/browse/COLLECTIONS-446を参照してください。

4

4 に答える 4

6

「比較」と「同等性」の概念を分離するために、Guava同等性クラスを使用できます。コンパレータの代わりに同等のサブクラスを受け入れる比較メソッド(AFAIK Guavaにはありません)を作成する必要がありますが、少なくともコードの混乱は少なくなり、同等の基準に基づいてコレクションを比較できます。

等価ラップされたオブジェクトのコレクションの使用(等価のwrapメソッドを参照)は、sharakanによって提案されたアダプターベースのソリューションに似ていますが、等価実装はアダプター実装から分離され、複数の等価基準を簡単に使用できるようになります。

于 2013-02-26T18:45:28.413 に答える
5

isEqualCollectionバージョン4以降に追加された新しいメソッドを使用できます。このメソッドは、インターフェース実装CollectionUtilsによって提供される外部比較メカニズムを使用します。Equator次のjavadocsを確認してください:CollectionUtils.isEqualCollection(...)およびEquator

于 2015-07-27T09:21:48.947 に答える
1

この方法が実際に優れているかどうかはわかりませんが、「別の方法」です...

元の2つのコレクションを取得し、各ベースオブジェクトのアダプターを含む新しいコレクションを作成します。アダプタは、に基づいて実装されている必要が.equals()あります。次に、通常のコレクションの等価性を使用して、アダプターのコレクションを比較できます。.hashCode()Name.calculateWeightedRank()

* 編集 *

Eclipseの標準hashCode/equals生成を使用しAdapterます。コードは、各ベースコレクションでadaptCollectionを呼び出し、次に2つの結果を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;
    }

}
于 2013-02-26T17:04:05.243 に答える
0

編集:古い答えを削除しました。

あなたが持っているもう一つのオプションは、次の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;
}

次に、重み付けして比較する必要のある追加のクラスを見つけたら、それらをコレクションに入れて、相互に比較することもできます。ただのアイデア。

于 2013-02-26T17:11:38.387 に答える