What is the best way to check two List lists for equality in C#

后端 未结 6 1781
误落风尘
误落风尘 2020-12-16 13:16

There are many ways to do this but I feel like I\'ve missed a function or something.

Obviously List == List will use Object.Equals() and re

6条回答
  •  误落风尘
    2020-12-16 13:43

    One can write a general purpose IEqualityComparer for sequences. A simple one:

    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()));
        }
    }
    

    A more fleshed out version: which should be better performing.

    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();
        }
    }
    

    This has a few features:

    1. The comparison is done from bottom to top. There is more probability for collections differing at the end in typical use-cases.

    2. An IEqualityComparer can be passed to base the comparison for items in the collection.

提交回复
热议问题