web-dev-qa-db-ja.com

2つのArrayListが異なるかどうかを確認するにはどうすればよいですか、何が変更されてもかまいません

2つのArrayListが互いに異なるかどうかを確認するにはどうすればよいですか?違いは何でも構いませんが、それらが同じではないかどうかを知りたいだけです。

私は毎分データベースからスコアリストを取得していますが、取得したスコアリストが1分前に取得したものと異なる場合にのみ、クライアントに送信します。

現在、ArrayListの値は、実際に作成したクラスです(名前、レベル、ランク、スコアを含む)。

equals()を実装する必要がありますか?

37
ufk

2つの配列リストに順序に関係なく同じ値が含まれているかどうかを確認する簡単な方法を次に示します。

 //the name of the method explains it well...
    public boolean isTwoArrayListsWithSameValues(ArrayList<Object> list1, ArrayList<Object> list2)
    {
        //null checking
        if(list1==null && list2==null)
            return true;
        if((list1 == null && list2 != null) || (list1 != null && list2 == null))
            return false;

        if(list1.size()!=list2.size())
            return false;
        for(Object itemList1: list1)
        {
            if(!list2.contains(itemList1))
                return false;
        }

        return true;
    }
9

「同一性」の定義について

Joachimが指摘したように、ほとんどのアプリケーションでは、 List.equals(Object o) 定義が機能します:

指定されたオブジェクトとこのリストが等しいかどうかを比較します。指定されたオブジェクトもリストであり、両方のリストが同じサイズであり、2つのリスト内の対応する要素のペアがすべて等しい場合にのみ、trueを返します。 (2つの要素e1e2は、(e1==null ? e2==null : e1.equals(e2))の場合に等しい。)つまり、2つのリストは、同じ順序で同じ要素が含まれている場合に等しいと定義されます。この定義により、equalsメソッドのさまざまな実装でListインターフェイスが適切に機能することが保証されます。

ただし、使用方法によっては、期待どおりに機能しない場合があります。たとえば、List<int[]>がある場合、配列はequalsからObjectを継承します。これは、参照IDとして同等性を定義します。

    List<int[]> list1 = Arrays.asList(new int[] { 1, 2, 3 });
    List<int[]> list2 = Arrays.asList(new int[] { 1, 2, 3 });
    System.out.println(list1.equals(list2)); // prints "false"

また、異なる型パラメーターを持つ2つのリストをequalsにすることができます。

    List<Number> list1 = new ArrayList<Number>();
    List<String> list2 = new ArrayList<String>();
    System.out.println(list1.equals(list2)); // prints "true"

また、リストには同じタイプの要素が含まれている必要があることにも触れました。要素が同じタイプではなく、equalsである別の例を次に示します。

    List<Object> list1 = new ArrayList<Object>();
    List<Object> list2 = new ArrayList<Object>();
    list1.add(new ArrayList<Integer>());
    list2.add(new LinkedList<String>());
    System.out.println(list1.equals(list2)); // prints "true"

したがって、平等があなたに何を意味するかを明確に定義しない限り、質問には非常に異なる答えが含まれることがあります。ただし、最も実用的な目的には、List.equalsで十分です。


equalsの実装について

更新後の情報は、List.equalsが問題なく動作することを示唆しています。提供要素がequalsを適切に実装する(上記のAPIドキュメントに従って、List<E>.equalsがnon _null-要素でE.equalsを呼び出すため) )。

したがって、この場合、たとえばList<Player>がある場合、o instanceof Playerがあり、関連するフィールドでPlayerを返すには、true@Override equals(Object o)でなければなりません。それらはすべてequals(参照型の場合)または==(プリミティブの場合)です。

もちろん、@Override equalsを使用するときは、@Override int hashCode()も使用する必要があります。かろうじて受け入れられる最小値はreturn 42;です。少し良いのはreturn name.hashCode();;です。最善の方法は、equalsを定義するすべてのフィールドを含む式を使用することです。適切なIDEはequals/hashCodeメソッドを自動的に生成できます。

こちらもご覧ください

  • 有効Java 2nd Edition
    • 項目8:等号をオーバーライドする場合は、一般契約に従います
    • 項目9:equalsをオーバーライドするときは常にハッシュコードをオーバーライドする

APIリンク

関連する質問

equals/hashCodeコンボの場合:

equals==の場合:

79

equals()を使用します。リスト内の要素がequals()を正しく実装している限り、正しい値を返します。

値の順序を無視する場合を除き、2つのSetオブジェクトに値をダンプし、equals()を使用して値を比較する必要があります。

12
Joachim Sauer

@Joachim Sauerが彼の答えで言及したように、リストが等しく、それらのコンテンツが等しく実装されていれば、equalsは機能するはずです。ただし、アイテムが同じ「順序」にない場合は、チェックに包含を使用しないため、機能しません。この意味で、@ jarnbjoで言及されている「厳密な」同等性をチェックします。

        //From Android's Arraylist implementation
        Iterator<?> it = that.iterator();
        for (int i = 0; i < s; i++) {
            Object eThis = a[i];
            Object eThat = it.next();
            if (eThis == null ? eThat != null : !eThis.equals(eThat)) {
                return false;
            }
        }

しかし、私は多少異なる振る舞いを望んでいました。注文などは気にしませんでした。私が望んだのは、2つに同じアイテムが含まれていないことを確認することだけでした。私の解決策、

    //first check that both are not null and are of same length. (not shown here)
    //if both match, pull out the big guns as below
    ...
    List<Object> comparedList = new ArrayList<>(listOne);
    comparedList.removeAll(listTwo);
    if(comparedList.size() != 0) //there are differences between the two

最初はremoveAllで、次にcontainsによって呼び出されるremoveAllで2回ループするため、パフォーマンスが低下します。

私のリストは短いことが保証されていたので、ヒットを気にしませんでした。

2
frostymarvelous

それらを文字列に変換してから、次のように比較できます

list1.toString().equals(list2.toString())
2
Robert Londo