在C#中检查两个List 列表是否相等的最佳方法是什么?

有很多方法可以做到这一点,但我觉得我错过了一个function或其他东西。

显然List == List将使用Object.Equals()并返回false

如果列表中的每个元素都相等并且出现在相反列表中的相同位置,那么我认为它们是相等的。 我正在使用值类型,但正确实现的Data对象应该以相同的方式工作(即我不是在寻找浅复制列表,只是内部每个对象的相同)。

我尝试过搜索,也有类似的问题,但我的问题是每个元素都是按照确切的顺序相等。

 Enumerable.SequenceEqual 

MSDN

邪恶的实施是

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

我把这个变化放在一起:

 private bool AreEqual(List x, List 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; } 

我的书呆子也爬了出去,所以我对SequenceEquals进行了性能测试,这个有一点点优势。

现在,要问的问题; 这个微小的,几乎可测量的性能增益值得将代码添加到代码库并维护它吗? 我非常怀疑它; o)

我敲了一个快速扩展方法:

 namespace ExtensionMethods { public static class MyExtensions { public static bool Matches(this List list1, List 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; } } } 

可以为序列编写通用的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(); } } 

这有一些function:

  1. 比较从下到上进行。 在典型的用例中,最终集合的可能性更大。

  2. 可以传递IEqualityComparer以对集合中的项进行比较。

使用linq SequenceEqual检查序列是否相等,因为Equals方法检查引用相等性。

 bool isEqual = list1.SequenceEqual(list2); 

SequenceEqual()方法将第二个I Enumerable序列作为参数,并逐个元素地执行与目标(第一)序列的比较。 如果两个序列包含相同数量的元素,并且第一个序列中的每个元素等于第二个序列中的对应元素(使用默认的相等比较器 ),则SequenceEqual() returns true 。 否则,返回false

或者如果你不关心元素顺序使用Enumerable.All方法:

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

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