18


3

2つのList <T>リストがC#で同等かどうかをチェックするための最良の方法は何ですか

これを行うには多くの方法がありますが、私は関数か何かを逃したような気がします。

明らかに List == List`は Object.Equals() を使って false`を返します。

リストのすべての要素が等しく、反対側のリストの同じ場所に存在する場合、それらは等しいと見なします。 値型を使用していますが、正しく実装されたDataオブジェクトも同じように機能するはずです(つまり、コピーされたリストの浅さを探しているのではなく、各オブジェクトの_value_が同じであることだけ)

私は検索してみましたが、同様の質問がありますが、私の質問は正確な順序ですべての要素が等しいことです。

6 Answer


39


Enumerable.SequenceEqual
http://msdn.microsoft.com/en-us/library/bb348567.aspx[MSDN]


3


悪の実装は

if(List1.Count == List2.Count){for(int i = 0; i <List1.Count; i){if(List1 [i]!= List2 [i]){falseを返します。 trueを返します。 falseを返します。


3


私はこのバリエーションをまとめました:

private bool AreEqual(List x、List y){//(x == y)の場合、同じリストまたはその両方がnull }

//(x == null || y == null){falseを返す。 }

//カウントが異なります。 (x.Count!= y.Count){falseを返す場合は等しくありません。 }

for(int i = 0; i <xCount; i){if(!x [i] .Equals(y [i])){falseを返す。 trueを返します。 }

私の中のオタクもクロールしたので、SequenceEqualsに対してパフォーマンステストを行いましたが、これは少し優位です。

今、尋ねるべき質問です。この小さな、ほぼ測定可能なパフォーマンスの向上は、コードをコードベースに追加して維持する価値がありますか? 私はそれをとても疑います; o)


2


私は簡単な拡張方法をノックアップしました:

名前空間ExtensionMethods {public static class MyExtensions {public static bool(this List list1、List list2)に一致します。{if(list1.Count!= list2.Count)はfalseを返します。 for(var i = 0; i <list1.Count; i){if(list1 [i]!= list2 [i])falseを返す。 trueを返します。 }}}


1


シーケンス用の汎用の `IEqualityComparer`を書くことができます。 簡単なもの:

public class SequenceEqualityComparer : IEqualityComparer>
{
    public bool Equals(IEnumerable x, IEnumerable y)
    {
        return x.SequenceEqual(y);
    }

    public int GetHashCode(IEnumerable obj)
    {
        return unchecked(obj.Aggregate(397, (x, y) => x * 31 + y.GetHashCode()));
    }
}

'' '' '

より肉付けされたバージョン:これはよりパフォーマンスが良いはずです。

public class SequenceEqualityComparer : EqualityComparer>,
                                           IEquatable>
{
    readonly IEqualityComparer comparer;

    public SequenceEqualityComparer(IEqualityComparer comparer = null)
    {
        this.comparer = comparer ?? EqualityComparer.Default;
    }

    public override bool Equals(IEnumerable x, IEnumerable y)
    {
        // safer to use ReferenceEquals as == could be overridden
        if (ReferenceEquals(x, y))
            return true;

        if (x == null || y == null)
            return false;

        var xICollection = x as ICollection;
        if (xICollection != null)
        {
            var yICollection = y as ICollection;
            if (yICollection != null)
            {
                if (xICollection.Count != yICollection.Count)
                    return false;

                var xIList = x as IList;
                if (xIList != null)
                {
                    var yIList = y as IList;
                    if (yIList != null)
                    {
                        // optimization - loops from bottom
                        for (int i = xIList.Count - 1; i >= 0; i--)
                            if (!comparer.Equals(xIList[i], yIList[i]))
                                return false;

                        return true;
                    }
                }
            }
        }

        return x.SequenceEqual(y, comparer);
    }

    public override int GetHashCode(IEnumerable sequence)
    {
        unchecked
        {
            int hash = 397;
            foreach (var item in sequence)
                hash = hash * 31 + comparer.GetHashCode(item);

            return hash;
        }
    }

    public bool Equals(SequenceEqualityComparer other)
    {
        if (ReferenceEquals(null, other))
            return false;

        if (ReferenceEquals(this, other))
            return true;

        return this.comparer.Equals(other.comparer);
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as SequenceEqualityComparer);
    }

    public override int GetHashCode()
    {
        return comparer.GetHashCode();
    }
}

これにはいくつかの機能があります。

  1. 比較は下から上へ行われます。 より多くの確率があります 典型的なユースケースで最後に異なるコレクションの場合。

  2. 「IEqualityComparer」を渡して、アイテムの比較のベースにすることができます コレクション内。


0


Equalsメソッドは参照の等価性をチェックするので、シーケンスの等価性をチェックするには* linq * `SequenceEqual`を使用してください。

bool isEqual = list1.SequenceEqual(list2);

`SequenceEqual()`メソッドはパラメータとして2番目のI`Enumerable`シーケンスを受け取り、ターゲット(最初の)シーケンスとの比較、* element-by-element *を実行します。 2つのシーケンスが*同数*の要素を含み、最初のシーケンスの各要素が2番目のシーケンスの対​​応する要素と等しい場合(_default equality comparer_を使用)、 `SequenceEqual()`はtrueを返します。 そうでなければ、 `false`が返されます。

あるいは要素の順序を気にしないのであれば `Enumerable.All`メソッドを使ってください:

var isEqual = list1.All(list2.Contains);

2番目のバージョンでは、 list2`が list1`よりも多くの要素を含んでいてもtrueを返すので、Countに対する別のチェックも必要です。