What is the best way to check two List lists fo

2019-01-24 01:02发布

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 return false.

If every element of the list is equal and present in the same location in the opposite list then I would consider them to be equal. I'm using value types, but a correctly implemented Data object should work in the same fashion (i.e I'm not looking for a shallow copied list, only that the value of each object within is the same).

I've tried searching and there are similar questions, but my question is an equality of every element, in an exact order.

6条回答
Viruses.
2楼-- · 2019-01-24 01:39

Evil implementation is

if (List1.Count == List2.Count)
{
   for(int i = 0; i < List1.Count; i++)
   {
      if(List1[i] != List2[i])
      {
         return false;
      }
   }
   return true;
}
return false;
查看更多
Luminary・发光体
3楼-- · 2019-01-24 01:43

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

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

    public int GetHashCode(IEnumerable<T> 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<T> : EqualityComparer<IEnumerable<T>>, 
                                           IEquatable<SequenceEqualityComparer<T>>
{
    readonly IEqualityComparer<T> comparer;

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

    public override bool Equals(IEnumerable<T> x, IEnumerable<T> 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<T>;
        if (xICollection != null)
        {
            var yICollection = y as ICollection<T>;
            if (yICollection != null)
            {
                if (xICollection.Count != yICollection.Count)
                    return false;

                var xIList = x as IList<T>;
                if (xIList != null)
                {
                    var yIList = y as IList<T>;
                    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<T> sequence)
    {
        unchecked
        {
            int hash = 397;
            foreach (var item in sequence)
                hash = hash * 31 + comparer.GetHashCode(item);

            return hash;
        }
    }

    public bool Equals(SequenceEqualityComparer<T> 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<T>);
    }

    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<T> can be passed to base the comparison for items in the collection.

查看更多
Melony?
4楼-- · 2019-01-24 01:52
Enumerable.SequenceEqual<TSource>

MSDN

查看更多
该账号已被封号
5楼-- · 2019-01-24 01:52

I knocked up a quick extension method:

namespace ExtensionMethods
{
    public static class MyExtensions
    {
        public static bool Matches<T>(this List<T> list1, List<T> list2)
        {
            if (list1.Count != list2.Count) return false;
            for (var i = 0; i < list1.Count; i++)
            {
                if (list1[i] != list2[i]) return false;
            }
            return true;
        }
    }   
}
查看更多
▲ chillily
6楼-- · 2019-01-24 01:52

Use linq SequenceEqual to check for sequence equality because Equals method checks for reference equality.

bool isEqual = list1.SequenceEqual(list2);

The SequenceEqual() method takes a second IEnumerable<T> sequence as a parameter, and performs a comparison, element-by-element, with the target (first) sequence. If the two sequences contain the same number of elements, and each element in the first sequence is equal to the corresponding element in the second sequence (using the default equality comparer) then SequenceEqual() returns true. Otherwise, false is returned.

Or if you don't care about elements order use Enumerable.All method:

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

The second version also requires another check for Count because it would return true even if list2 contains more elements than list1.

查看更多
三岁会撩人
7楼-- · 2019-01-24 02:01

I put together this variation:

private bool AreEqual<T>(List<T> x, List<T> y)
{
    // same list or both are null
    if (x == y)
    {
        return true;
    }

    // one is null (but not the other)
    if (x== null || y == null)
    {
        return false;
    }

    // count differs; they are not equal
    if (x.Count != y.Count)
    {
        return false;
    }

    for (int i = 0; i < x.Count; i++)
    {
        if (!x[i].Equals(y[i]))
        {
            return false;
        }
    }
    return true;
}

The nerd in me also crawled out so I did a performance test against SequenceEquals, and this one has a slight edge.

Now, the question to ask; is this tiny, almost measurable performance gain worth adding the code to the code base and maintaining it? I very much doubt it ;o)

查看更多
登录 后发表回答