278

2つの大規模な(> 50.000アイテム)を比較するのに最も速く(そして最もリソースを消費しない)、結果として以下のような2つのリストがあります。

  1. 最初のリストには表示されるが、2番目のリストには表示されないアイテム
  2. 2番目のリストには表示されるが、最初のリストには表示されないアイテム

現在、ListまたはIReadOnlyCollectionを使用しており、linqクエリでこの問題を解決しています。

var list1 = list.Where(i => !list2.Contains(i)).ToList();
var list2 = list2.Where(i => !list.Contains(i)).ToList();

しかし、これは私が望むほどうまく機能しません。たくさんのリストを処理する必要があるので、これをより速く、より少ないリソースを消費するようにするアイデアはありますか?

4

16 に答える 16

549

使用Except:

var firstNotSecond = list1.Except(list2).ToList();
var secondNotFirst = list2.Except(list1).ToList();

実際にはこれよりもわずかに高速なアプローチがあると思いますが、これでも O(N * M) アプローチよりもはるかに高速になります。

これらを組み合わせたい場合は、上記と return ステートメントを使用してメソッドを作成できます。

return !firstNotSecond.Any() && !secondNotFirst.Any();

注意すべき点の 1 つは、質問の元のコードとここでの解決策との間に結果の違いあることです。1 つのリストにのみ含まれる重複要素は、私のコードでは 1 回だけ報告されますが、多く報告されます。元のコードで発生する回数。

たとえば、 と のリストの[1, 2, 2, 2, 3]場合[1]、「list1 にはあるが list2 にはない要素」は、元のコードは になります[2, 2, 2, 3]。私のコードでは、それはちょうど[2, 3]. 多くの場合、これは問題になりませんが、注意する価値があります。

于 2012-10-09T08:31:12.910 に答える
42

より効率的に使用することになりますEnumerable.Except

var inListButNotInList2 = list.Except(list2);
var inList2ButNotInList = list2.Except(list);

このメソッドは、遅延実行を使用して実装されます。つまり、たとえば次のように書くことができます。

var first10 = inListButNotInList2.Take(10);

内部的に a を使用しSet<T>てオブジェクトを比較するため、効率的でもあります。最初に 2 番目のシーケンスからすべての個別の値を収集し、次に最初のシーケンスの結果をストリーミングして、それらが以前に見られていないことを確認することによって機能します。

于 2012-10-09T08:31:44.763 に答える
10

結果の大文字と小文字を区別しないようにする場合は、次のようにします。

List<string> list1 = new List<string> { "a.dll", "b1.dll" };
List<string> list2 = new List<string> { "A.dll", "b2.dll" };

var firstNotSecond = list1.Except(list2, StringComparer.OrdinalIgnoreCase).ToList();
var secondNotFirst = list2.Except(list1, StringComparer.OrdinalIgnoreCase).ToList();

firstNotSecondb1.dllが含まれます

secondNotFirstb2.dllが含まれます

于 2016-01-20T16:32:47.327 に答える
4

この問題ではありませんが、リストが等しいかどうかを比較するコードを次に示します。同一のオブジェクト:

public class EquatableList<T> : List<T>, IEquatable<EquatableList<T>> where    T : IEquatable<T>

/// <summary>
/// True, if this contains element with equal property-values
/// </summary>
/// <param name="element">element of Type T</param>
/// <returns>True, if this contains element</returns>
public new Boolean Contains(T element)
{
    return this.Any(t => t.Equals(element));
}

/// <summary>
/// True, if list is equal to this
/// </summary>
/// <param name="list">list</param>
/// <returns>True, if instance equals list</returns>
public Boolean Equals(EquatableList<T> list)
{
    if (list == null) return false;
    return this.All(list.Contains) && list.All(this.Contains);
}
于 2014-01-20T14:26:52.527 に答える
3

この方法を試してください:

var difList = list1.Where(a => !list2.Any(a1 => a1.id == a.id))
            .Union(list2.Where(a => !list1.Any(a1 => a1.id == a.id)));
于 2012-10-09T08:32:30.580 に答える
2

このコードを使用して、数百万のレコードを持つ 2 つのリストを比較しました。

この方法はそれほど時間はかかりません

    //Method to compare two list of string
    private List<string> Contains(List<string> list1, List<string> list2)
    {
        List<string> result = new List<string>();

        result.AddRange(list1.Except(list2, StringComparer.OrdinalIgnoreCase));
        result.AddRange(list2.Except(list1, StringComparer.OrdinalIgnoreCase));

        return result;
    }
于 2016-08-09T07:35:35.163 に答える