简体   繁体   English

检查两个List的最佳方法是什么 <T> C#中的相等列表

[英]What is the best way to check two List<T> lists for equality in C#

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 . 显然List == List将使用Object.Equals()并返回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 (ie I'm not looking for a shallow copied list, only that the value of each object within is the same). 我正在使用值类型,但正确实现的Data对象应该以相同的方式工作(即我不是在寻找浅复制列表,只是内部每个对象的相同)。

I've tried searching and there are similar questions, but my question is an equality of every element, in an exact order. 我尝试过搜索,也有类似的问题,但我的问题是每个元素的确切顺序。

Enumerable.SequenceEqual<TSource>

MSDN

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;

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. 我的书呆子也爬了出去,所以我对SequenceEquals进行了性能测试,这个有一点点优势。

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) 我非常怀疑它; o)

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

One can write a general purpose IEqualityComparer<T> for sequences. 可以为序列编写通用的IEqualityComparer<T> 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. 可以传递IEqualityComparer<T>以对集合中的项进行比较。

Use linq SequenceEqual to check for sequence equality because Equals method checks for reference equality. 使用linq SequenceEqual检查序列是否相等,因为Equals方法检查引用相等性。

bool isEqual = list1.SequenceEqual(list2);

The SequenceEqual() method takes a second I Enumerable<T> sequence as a parameter, and performs a comparison, element-by-element , with the target (first) sequence. SequenceEqual()方法将第二个I Enumerable<T>序列作为参数,并逐个元素地执行与目标(第一)序列的比较。 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 . 如果两个序列包含相同数量的元素,并且第一个序列中的每个元素等于第二个序列中的相应元素(使用默认的相等比较器 ),则SequenceEqual() returns true Otherwise, false is returned. 否则,返回false

Or if you don't care about elements order use Enumerable.All method: 或者如果你不关心元素顺序使用Enumerable.All方法:

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 . 第二个版本还需要对Count进行另一次检查,因为即使list2包含的元素多于list1它也会返回true。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在C#中返回两个列表的最佳方法是什么? - What is the best way to return two lists in C#? 在 C# 中比较两个 DateTime 的相等性的最佳方法是什么……但只能达到一定的精度? - What's the best way to compare the equality of two DateTime's in C#… but only to a certain precision? 在C#中比较复杂对象的两个列表的最佳方法是什么 - What is the best way to compare two list of complex object in c# 比较两个词典的最佳方法 <T> 为了平等 - Best way to compare two Dictionary<T> for equality 查找不在两个列表中的值的最佳方法C# - Best way to find values not in two lists c# 在C#中比较2个整数列表/数组的最佳方法是什么? - What is the best way to compare 2 integer lists / array in C# 根据属性之一检查两个实体集是否相等的最佳方法? - Best way to check two EntitySets equality basied on one of their proprties? 在C#中检查浮点变量的确切值相等的正确方法是什么? - What is the right way to check floating-point variables for exact value equality in c#? 在C#中,转换List的最佳方法是什么 <T> 到SortedDictionary <string, T> ? - In C#, what is the best way to convert a List<T> to a SortedDictionary<string, T>? C# 不同 object 类型的列表:比 Zip 更好的方法来检查相等性 - C# List of different object types: Better way than Zip to check equality
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM