152

私は2つArrayListのタイプAnswer(自作クラス)を持っています。

2つのリストを比較して、同じ内容が含まれているかどうかを確認したいと思いますが、順序は関係ありません。

例:

//These should be equal.
ArrayList<String> listA = {"a", "b", "c"}
ArrayList<String> listB = {"b", "c", "a"}

List.equals同じサイズ、内容、要素の順序が含まれている場合、2つのリストは等しいと述べています。同じことをしたいのですが、順序は関係ありません。

これを行う簡単な方法はありますか?または、ネストされたforループを実行し、両方のリストの各インデックスを手動でチェックする必要がありますか?

注:それらArrayListを別のタイプのリストに変更することはできません。そのままにしておく必要があります。

4

18 に答える 18

167

おそらく、リストの最も簡単な方法は次のとおりです

listA.containsAll(listB) && listB.containsAll(listA)
于 2012-11-21T20:33:58.453 に答える
139

を使用して両方のリストを並べ替えてCollections.sort()から、equalsメソッドを使用できます。少し良い解決策は、注文する前に最初に同じ長さであるかどうかを確認し、そうでない場合は等しくない、次に並べ替えてから等しいを使用することです。たとえば、文字列のリストが2つある場合、次のようになります。

public  boolean equalLists(List<String> one, List<String> two){     
    if (one == null && two == null){
        return true;
    }

    if((one == null && two != null) 
      || one != null && two == null
      || one.size() != two.size()){
        return false;
    }

    //to avoid messing the order of the lists we will use a copy
    //as noted in comments by A. R. S.
    one = new ArrayList<String>(one); 
    two = new ArrayList<String>(two);   

    Collections.sort(one);
    Collections.sort(two);      
    return one.equals(two);
}
于 2012-11-21T20:06:05.683 に答える
100

ApacheCommonsCollectionsが再び

List<String> listA = Arrays.asList("a", "b", "b", "c");
List<String> listB = Arrays.asList("b", "c", "a", "b");
System.out.println(CollectionUtils.isEqualCollection(listA, listB)); // true

 

List<String> listC = Arrays.asList("a", "b", "c");
List<String> listD = Arrays.asList("a", "b", "c", "c");
System.out.println(CollectionUtils.isEqualCollection(listC, listD)); // false

ドキュメント:

org.apache.commons.collections4.CollectionUtils

public static boolean isEqualCollection(java.util.Collection a,
                                        java.util.Collection b)

true指定されたCollectionsに、まったく同じカーディナリティを持つまったく同じ要素が含まれている場合に 戻ります。

つまり、aまたはb各要素eについて、aのeのカーディナリティがbのeカーディナリティと等しい場合。

パラメーター:

  • a-最初のコレクションは、null
  • b-2番目のコレクションは、null

戻り値: trueコレクションに同じカーディナリティを持つ同じ要素が含まれている場合。

于 2014-03-24T19:53:12.517 に答える
14
// helper class, so we don't have to do a whole lot of autoboxing
private static class Count {
    public int count = 0;
}

public boolean haveSameElements(final List<String> list1, final List<String> list2) {
    // (list1, list1) is always true
    if (list1 == list2) return true;

    // If either list is null, or the lengths are not equal, they can't possibly match 
    if (list1 == null || list2 == null || list1.size() != list2.size())
        return false;

    // (switch the two checks above if (null, null) should return false)

    Map<String, Count> counts = new HashMap<>();

    // Count the items in list1
    for (String item : list1) {
        if (!counts.containsKey(item)) counts.put(item, new Count());
        counts.get(item).count += 1;
    }

    // Subtract the count of items in list2
    for (String item : list2) {
        // If the map doesn't contain the item here, then this item wasn't in list1
        if (!counts.containsKey(item)) return false;
        counts.get(item).count -= 1;
    }

    // If any count is nonzero at this point, then the two lists don't match
    for (Map.Entry<String, Count> entry : counts.entrySet()) {
        if (entry.getValue().count != 0) return false;
    }

    return true;
}
于 2012-11-21T21:02:55.890 に答える
13

私はこれらの答えがトリックを逃していると思います。

Blochは、彼の本質的で、素晴らしく、簡潔な効果的なJavaで、項目47のタイトル「ライブラリを知って使用する」、「要約すると、車輪の再発明をしないでください」と述べています。そして、彼はいくつかの非常に明確な理由を挙げています。

ここにはCollectionUtils、Apache Commons Collectionsライブラリのメソッドを提案するいくつかの回答がありますが、この質問に答える最も美しくエレガントな方法を見つけたものはありません。

Collection<Object> culprits = CollectionUtils.disjunction( list1, list2 );
if( ! culprits.isEmpty() ){
  // ... do something with the culprits, i.e. elements which are not common

}

犯人:すなわち、両方に共通ではない要素Lists。とを使用すると、どの犯人がどの犯人に属し、どの犯人に属するかを判断list1するのlist2は比較的簡単です。ただし、{"a"、 "a"、 "b"}と{"a"、 "b"、 "b"}のような場合は、これがソフトウェアの障害ではないことを除いて、 バラバラになる傾向があります。目的のタスクの微妙さ/あいまいさの性質に固有です。CollectionUtils.intersection( list1, culprits )CollectionUtils.intersection( list2, culprits )
disjunction

Apacheエンジニアによって作成されたこのようなタスクについては、いつでもソースコード(l。287)を調べることができます。彼らのコードを使用することの利点の1つは、多くのエッジケースや落とし穴が予想され、対処されて、徹底的に試行およびテストされていることです。必要に応じて、このコードをコピーして心ゆくまで微調整できます。


NB私は最初、CollectionUtilsどのメソッドもオーバーロードされたバージョンを提供せず、独自のバージョンを課すことができることに失望しましたComparator(したがってequals、目的に合わせて再定義できます)。

しかし、collections4 4.0から、Equator「タイプTのオブジェクト間の同等性を決定する」新しいクラスがあります。collections4 CollectionUtils.javaのソースコードを調べると、いくつかのメソッドでこれを使用しているようですが、私が理解できる限り、これはファイルの先頭にあるCardinalityHelperクラスを使用するメソッドには適用できません...インクルードdisjunctionintersection

Apacheの人々は、それが自明ではないため、まだこれに慣れていないと思います。「AbstractEquatingCollection」クラスのようなものを作成する必要があります。このクラスは、その要素の固有equalshashCodeメソッドを使用する代わりに、それらを使用する必要があります。 、などのEquatorすべての基本的なメソッドの。実際、ソースコードを見ると、NBは実装されておらず、そのような抽象サブクラスも実装されていません。実装されています。かなりの頭痛。addcontainsAbstractCollectionaddAbstractSetHashSetArrayListadd

その間、この空間を見てください。明らかな暫定的な解決策は、すべての要素を特注のラッパークラスでラップし、必要な種類の同等性を使用equalshashCodeて実装することです...次にCollections、これらのラッパーオブジェクトを操作します。

于 2016-12-09T20:25:09.573 に答える
10

アイテムのカーディナリティが重要でない場合(つまり、繰り返される要素は1つと見なされます)、並べ替える必要なしにこれを行う方法があります。

boolean result = new HashSet<>(listA).equals(new HashSet<>(listB));

Setこれにより、それぞれからoutが作成され、 (もちろん)順序付けを無視するのメソッドがList使用されます。HashSetequals

カーディナリティが重要な場合は、List;が提供する施設に限定する必要があります。その場合、@jschoenの答えの方が適しています。

于 2012-11-21T20:33:24.120 に答える
6

これは@cHaoソリューションに基づいています。いくつかの修正とパフォーマンスの改善を含めました。これは、等順序コピーソリューションの約2倍の速度で実行されます。すべてのコレクションタイプで機能します。空のコレクションとnullは等しいと見なされます。あなたの利点に使用してください;)

/**
 * Returns if both {@link Collection Collections} contains the same elements, in the same quantities, regardless of order and collection type.
 * <p>
 * Empty collections and {@code null} are regarded as equal.
 */
public static <T> boolean haveSameElements(Collection<T> col1, Collection<T> col2) {
    if (col1 == col2)
        return true;

    // If either list is null, return whether the other is empty
    if (col1 == null)
        return col2.isEmpty();
    if (col2 == null)
        return col1.isEmpty();

    // If lengths are not equal, they can't possibly match
    if (col1.size() != col2.size())
        return false;

    // Helper class, so we don't have to do a whole lot of autoboxing
    class Count
    {
        // Initialize as 1, as we would increment it anyway
        public int count = 1;
    }

    final Map<T, Count> counts = new HashMap<>();

    // Count the items in col1
    for (final T item : col1) {
        final Count count = counts.get(item);
        if (count != null)
            count.count++;
        else
            // If the map doesn't contain the item, put a new count
            counts.put(item, new Count());
    }

    // Subtract the count of items in col2
    for (final T item : col2) {
        final Count count = counts.get(item);
        // If the map doesn't contain the item, or the count is already reduced to 0, the lists are unequal 
        if (count == null || count.count == 0)
            return false;
        count.count--;
    }

    // At this point, both collections are equal.
    // Both have the same length, and for any counter to be unequal to zero, there would have to be an element in col2 which is not in col1, but this is checked in the second loop, as @holger pointed out.
    return true;
}
于 2013-12-01T20:31:31.720 に答える
6

リストをGuavaのマルチセットに変換すると非常にうまくいきます。それらは順序に関係なく比較され、重複する要素も考慮されます。

static <T> boolean equalsIgnoreOrder(List<T> a, List<T> b) {
    return ImmutableMultiset.copyOf(a).equals(ImmutableMultiset.copyOf(b));
}

assert equalsIgnoreOrder(ImmutableList.of(3, 1, 2), ImmutableList.of(2, 1, 3));
assert !equalsIgnoreOrder(ImmutableList.of(1), ImmutableList.of(1, 1));
于 2016-05-13T12:26:01.640 に答える
5

コンピューターやプログラミング言語がない場合、これを自分でどのように行うかを考えてください。私はあなたに要素の2つのリストを与えます、そしてあなたはそれらが同じ要素を含んでいるかどうか私に言わなければなりません。どうしますか?

上記のように、1つのアプローチは、リストを並べ替えてから、要素ごとに移動して、それらが等しいかどうかを確認することです(これがList.equals機能します)。これは、リストの変更が許可されているか、リストのコピーが許可されていることを意味します。割り当てがわからないと、どちらか/両方が許可されているかどうかわかりません。

別のアプローチは、各要素が表示される回数を数えて、各リストを調べることです。両方のリストの最後のカウントが同じである場合、それらは同じ要素を持っています。そのためのコードは、各リストをのマップに変換してから、2つのマップelem -> (# of times the elem appears in the list)を呼び出すequalsことです。マップがHashMapである場合、それらの変換のそれぞれは、比較と同様にO(N)操作です。これにより、余分なメモリがいくらか犠牲になりますが、時間の点で非常に効率的なアルゴリズムが得られます。

于 2012-11-21T20:22:46.960 に答える
5

私はこれと同じ問題を抱えていて、別の解決策を思いつきました。これは、重複が含まれている場合にも機能します。

public static boolean equalsWithoutOrder(List<?> fst, List<?> snd){
  if(fst != null && snd != null){
    if(fst.size() == snd.size()){
      // create copied lists so the original list is not modified
      List<?> cfst = new ArrayList<Object>(fst);
      List<?> csnd = new ArrayList<Object>(snd);

      Iterator<?> ifst = cfst.iterator();
      boolean foundEqualObject;
      while( ifst.hasNext() ){
        Iterator<?> isnd = csnd.iterator();
        foundEqualObject = false;
        while( isnd.hasNext() ){
          if( ifst.next().equals(isnd.next()) ){
            ifst.remove();
            isnd.remove();
            foundEqualObject = true;
            break;
          }
        }

        if( !foundEqualObject ){
          // fail early
          break;
        }
      }
      if(cfst.isEmpty()){ //both temporary lists have the same size
        return true;
      }
    }
  }else if( fst == null && snd == null ){
    return true;
  }
  return false;
}

他のいくつかのソリューションと比較した利点:

  • O(N²)の複雑さよりも小さい(ここでの他の回答のソリューションと比較した実際のパフォーマンスはテストしていませんが)。
  • 早く終了します。
  • nullをチェックします。
  • 重複が含まれている場合でも機能します。配列[1,2,3,3]と別の配列がある[1,2,2,3]場合、ここでのほとんどのソリューションは、順序を考慮しない場合は同じであると示しています。このソリューションは、一時リストから等しい要素を削除することでこれを回避します。
  • 意味的平等(equals)を使用し、参照平等(==)は使用しません。
  • itensはソートされないためimplement Comparable、このソリューションが機能するために(によって)ソート可能である必要はありません。
于 2015-07-24T12:31:04.583 に答える
3

コレクションを並べ替えたくなく、["A""B""C"]が["B""B" "A" "C"]と等しくないという結果が必要な場合は、

l1.containsAll(l2)&&l2.containsAll(l1)

十分ではありません、あなたはおそらくサイズもチェックする必要があります:

    List<String> l1 =Arrays.asList("A","A","B","C");
    List<String> l2 =Arrays.asList("A","B","C");
    List<String> l3 =Arrays.asList("A","B","C");

    System.out.println(l1.containsAll(l2)&&l2.containsAll(l1));//cautions, this will be true
    System.out.println(isListEqualsWithoutOrder(l1,l2));//false as expected

    System.out.println(l3.containsAll(l2)&&l2.containsAll(l3));//true as expected
    System.out.println(isListEqualsWithoutOrder(l2,l3));//true as expected


    public static boolean isListEqualsWithoutOrder(List<String> l1, List<String> l2) {
        return l1.size()==l2.size() && l1.containsAll(l2)&&l2.containsAll(l1);
}
于 2017-02-20T08:54:25.987 に答える
2

CollectionUtils減算メソッドを活用するソリューション:

import static org.apache.commons.collections15.CollectionUtils.subtract;

public class CollectionUtils {
  static public <T> boolean equals(Collection<? extends T> a, Collection<? extends T> b) {
    if (a == null && b == null)
      return true;
    if (a == null || b == null || a.size() != b.size())
      return false;
    return subtract(a, b).size() == 0 && subtract(a, b).size() == 0;
  }
}
于 2014-01-28T11:12:04.407 に答える
1

順序が気になる場合は、equalsメソッドを使用してください。

list1.equals(list2)

注文を気にしない場合は、これを使用してください

Collections.sort(list1);
Collections.sort(list2);      
list1.equals(list2)
于 2016-11-24T13:13:10.360 に答える
1

1行の方法:)

  1. コレクションのアイテムは、インターフェイスComparable <?を実装していません。スーパーT>

     static boolean isEqualCollection(Collection<?> a, Collection<?> b) {
         return a == b || (a != null && b != null && a.size() == b.size()
             && a.stream().collect(Collectors.toMap(Function.identity(), s -> 1L, Long::sum)).equals(b.stream().collect(Collectors.toMap(Function.identity(), s -> 1L, Long::sum))));
     }
    
  2. コレクションのアイテムは、インターフェイスComparable <?を実装します。スーパーT>

     static <T extends Comparable<? super T>> boolean  isEqualCollection2(Collection<T> a, Collection<T> b) {
       return a == b || (a != null && b != null && a.size() == b.size() && a.stream().sorted().collect(Collectors.toList()).equals(b.stream().sorted().collect(Collectors.toList())));
     }
    
  3. https://github.com/retrostreams/android-retrostreamsを介してAndroid5とAndroid6をサポートする

    static boolean isEqualCollection(Collection<?> a, Collection<?> b) {
     return a == b || (a != null && b != null && a.size() == b.size()
             && StreamSupport.stream(a).collect(Collectors.toMap(Function.identity(), s->1L, Longs::sum)).equals(StreamSupport.stream(b).collect(Collectors.toMap(Function.identity(), s->1L, Longs::sum))));
    }
    

////テストケース

    boolean isEquals1 = isEqualCollection(null, null); //true
    boolean isEquals2 = isEqualCollection(null, Arrays.asList("1", "2")); //false
    boolean isEquals3 = isEqualCollection(Arrays.asList("1", "2"), null); //false
    boolean isEquals4 = isEqualCollection(Arrays.asList("1", "2", "2"), Arrays.asList("1", "1", "2")); //false
    boolean isEquals5 = isEqualCollection(Arrays.asList("1", "2"), Arrays.asList("2", "1")); //true
    boolean isEquals6 = isEqualCollection(Arrays.asList("1", 2.0), Arrays.asList(2.0, "1")); //true
    boolean isEquals7 = isEqualCollection(Arrays.asList("1", 2.0, 100L), Arrays.asList(2.0, 100L, "1")); //true
    boolean isEquals8 = isEqualCollection(Arrays.asList("1", null, 2.0, 100L), Arrays.asList(2.0, null, 100L, "1")); //true
于 2020-09-16T03:46:58.963 に答える
0

両方の長所[@DiddiZ、@ Chalkos]:これは主に@Chalkosメソッドに基づいていますが、バグ(ifst.next())を修正し、初期チェック(@DiddiZから取得)を改善し、最初のコレクションをコピーします(2番目のコレクションのコピーからアイテムを削除するだけです)。

ハッシュ関数や並べ替えを必要とせず、不平等に早期に存在できるようにすることで、これはこれまでで最も効率的な実装です。それは、コレクションの長さが数千以上で、非常に単純なハッシュ関数がない限りです。

public static <T> boolean isCollectionMatch(Collection<T> one, Collection<T> two) {
    if (one == two)
        return true;

    // If either list is null, return whether the other is empty
    if (one == null)
        return two.isEmpty();
    if (two == null)
        return one.isEmpty();

    // If lengths are not equal, they can't possibly match
    if (one.size() != two.size())
        return false;

    // copy the second list, so it can be modified
    final List<T> ctwo = new ArrayList<>(two);

    for (T itm : one) {
        Iterator<T> it = ctwo.iterator();
        boolean gotEq = false;
        while (it.hasNext()) {
            if (itm.equals(it.next())) {
                it.remove();
                gotEq = true;
                break;
            }
        }
        if (!gotEq) return false;
    }
    // All elements in one were found in two, and they're the same size.
    return true;
}
于 2016-01-08T12:00:10.967 に答える
0

これは、null値を含む可能性のある配列リストの同等性をチェックする別の方法です。

List listA = Arrays.asList(null, "b", "c");
List listB = Arrays.asList("b", "c", null);

System.out.println(checkEquality(listA, listB)); // will return TRUE


private List<String> getSortedArrayList(List<String> arrayList)
{
    String[] array = arrayList.toArray(new String[arrayList.size()]);

    Arrays.sort(array, new Comparator<String>()
    {
        @Override
        public int compare(String o1, String o2)
        {
            if (o1 == null && o2 == null)
            {
                return 0;
            }
            if (o1 == null)
            {
                return 1;
            }
            if (o2 == null)
            {
                return -1;
            }
            return o1.compareTo(o2);
        }
    });

    return new ArrayList(Arrays.asList(array));
}

private Boolean checkEquality(List<String> listA, List<String> listB)
{
    listA = getSortedArrayList(listA);
    listB = getSortedArrayList(listB);

    String[] arrayA = listA.toArray(new String[listA.size()]);
    String[] arrayB = listB.toArray(new String[listB.size()]);

    return Arrays.deepEquals(arrayA, arrayB);
}
于 2016-08-02T14:28:10.630 に答える
0

これに対する私の解決策。それほどクールではありませんが、うまく機能します。

public static boolean isEqualCollection(List<?> a, List<?> b) {

    if (a == null || b == null) {
        throw new NullPointerException("The list a and b must be not null.");
    }

    if (a.size() != b.size()) {
        return false;
    }

    List<?> bCopy = new ArrayList<Object>(b);

    for (int i = 0; i < a.size(); i++) {

        for (int j = 0; j < bCopy.size(); j++) {
            if (a.get(i).equals(bCopy.get(j))) {
                bCopy.remove(j);
                break;
            }
        }
    }

    return bCopy.isEmpty();
}
于 2019-01-03T02:23:11.370 に答える
-1

その場合、リスト{"a"、"b"}と{"b"、"a"}は同じです。また、{"a"、"b"}と{"b"、 "a"、"c"}は等しくありません。複雑なオブジェクトのリストを使用する場合は、 containsAllが内部で使用するため、 equalsメソッドをオーバーライドすることを忘れないでください。

if (oneList.size() == secondList.size() && oneList.containsAll(secondList)){
        areEqual = true;
}
于 2016-12-12T14:39:22.787 に答える