检查两个List 是否相等的最快方法

我有两个列表

ListAListB都有1000条记录。

Emp是Employee Class的对象。 以下是我的Employee课程

 public class Employee { int ID = 0; string Name = String.Empty; string Dept = String.Empty; string Address = String.Empty; int Age = 0; string Email = String.Empty; } 

我想validation两个列表是否相等。 Emp对象可以按不同顺序放置。 此外,可能有几个Emp对象在列表中具有完全相同的信息。 我也必须核实这些。

我尝试对列表进行排序并使用SequenceEqual进行比较

 Enumerable.SequenceEqual(ListA.OrderBy(s => s), ListB.OrderBy(s => s) 

我收到了以下错误

 At least one object must implement IComparable. Exception Stack trace is as below at System.Collections.Comparer.Compare(Object a, Object b) at System.Collections.Generic.ObjectComparer`1.Compare(T x, T y) at System.Linq.EnumerableSorter`2.CompareKeys(Int32 index1, Int32 index2) at System.Linq.EnumerableSorter`1.QuickSort(Int32[] map, Int32 left, Int32 right) at System.Linq.EnumerableSorter`1.Sort(TElement[] elements, Int32 count) at System.Linq.OrderedEnumerable`1.d__0.MoveNext() at System.Linq.Enumerable.SequenceEqual[TSource](IEnumerable`1 first, IEnumerable`1 second, IEqualityComparer`1 comparer) at System.Linq.Enumerable.SequenceEqual[TSource](IEnumerable`1 first, IEnumerable`1 second) 

我该如何实现呢? 如果你们能够以最快的方式为我提供这样做会更好,因为List中的对象数量可能会增加到1000万。 谢谢你的帮助 !

编辑:每个员工都必须在两个列表中,顺序无所谓。 但是,如果ListA包含相同的雇员对象5次(这意味着一些重复的条目),并且ListB包含雇员对象4次,则ListA和ListB不相等。

最好的复杂性是O(N)使用HashSet实现之后:

实现GetHashCode和Equals的类:

 public class Employee { public int ID = 0; public string Name = String.Empty; public string Dept = String.Empty; public string Address = String.Empty; public int Age = 0; public string Email = String.Empty; public override int GetHashCode() { return ID.GetHashCode() ^ (Name ?? String.Empty).GetHashCode() ^ (Dept ?? String.Empty).GetHashCode() ^ (Address ?? String.Empty).GetHashCode() ^ Age.GetHashCode() ^ (Email ?? String.Empty).GetHashCode() ; } public override bool Equals(object obj) { Employee other = obj as Employee; if (obj == null) return false; return ID == other.ID && Name == other.Name && Dept == other.Dept && Address == other.Address && Age == other.Age && Email == other.Email; } } 

比较列表的function:

 public static bool CompareLists(List list1, List list2) { if (list1 == null || list2 == null) return list1 == list2; if (list1.Count != list2.Count) return false; Dictionary hash = new Dictionary(); foreach (Employee employee in list1) { if (hash.ContainsKey(employee)) { hash[employee]++; } else { hash.Add(employee, 1); } } foreach (Employee employee in list2) { if (!hash.ContainsKey(employee) || hash[employee] == 0) { return false; } hash[employee]--; } return true; } 

您可以将SequenceEqual与自定义IEqualityComparer

 class EmployeeComparer : IEqualityComparer { public bool Equals(Employee x, Employee y) { if (x == null || y == null) return false; bool equals = x.ID==y.ID && x.Name == y.Name && x.Dept == y.Dept && x.Address == y.Address && x.Age == y.Age && x.Email == y.Email; return equals; } public int GetHashCode(Employee obj) { if (obj == null) return int.MinValue; int hash = 19; hash = hash + obj.ID.GetHashCode(); hash = hash + obj.Name.GetHashCode(); hash = hash + obj.Dept.GetHashCode(); hash = hash + obj.Address.GetHashCode(); hash = hash + obj.Age.GetHashCode(); hash = hash + obj.Email.GetHashCode(); return hash; } } 

现在它很简单:

 listA.SequenceEqual(ListB, new EmployeeComparer()); 

如果订单不重要且您只想知道所有员工是否都在两个列表中,您可以使用HashSet.SetEquals来确定两个列表是否包含相同的人员:

 var empComparer = new EmployeeComparer(); bool bothEqual = new HashSet(ListA, empComparer) .SetEquals(new HashSet(ListB, empComparer)); 

如果列表中的数字将变得非常大(10M),您可能不得不考虑查找的并行化以获得可接受的查询时间。

考虑使用PLINQ 。

你对’平等’的意思更清楚一点是好的。 等价检查有多复杂? 您是在检查对象是否相同或对象是否相同?

另一个考虑是这个; 如果元素的数量变得很大,你能考虑将这个检查从.NET转移到你的数据库 – 也许作为一个存储过程? 您可能会发现它在那里执行效率更高。

将列表缩减为标量类型:int,string,….

 L1.Select(x => xK).ToArray() 

使用except方法

 L1.Select(x => xK).ToArray().Except(L1.Select(x => xK).ToArray()) 

如果结果集的计数为0,则List等于

 L1.Select(x => xK).ToArray().Except(L1.Select(x => xK).ToArray()).Count() 

全部一起

 public class Program { public static void Main(String[] args) { List L1 = new List{ new O {K = 1, V = "abcd"}, new O {K = 2, V = "efgh"} }; List L2 = new List{ new O {K = 1, V = "abcd"} }; List L3 = new List{ new O {K = 1, V = "abcd"}, new O {K = 3, V = "ijkl"} }; List L4 = new List{ new O {K = 2, V = "efgh"}, new O {K = 1, V = "abcd"} }; Console.WriteLine(L1.Select(x => xK).ToArray().Except(L1.Select(x => xK).ToArray()).Count()); Console.WriteLine(L1.Select(x => xK).ToArray().Except(L2.Select(x => xK).ToArray()).Count()); Console.WriteLine(L1.Select(x => xK).ToArray().Except(L3.Select(x => xK).ToArray()).Count()); Console.WriteLine(L1.Select(x => xK).ToArray().Except(L4.Select(x => xK).ToArray()).Count()); } } public class O { public int K { get; set; } public String V { get; set; } } 

究竟是什么意思。
在Employee类上实现IComparable
还需要覆盖Equals
由于可能会对GetHashCode进行大量调用以保存它并仅计算更改。
经测试

IComparable接口

 public MainWindow() { InitializeComponent(); List PLa = new List(); List PLb = new List(); PLa.Add(new Person { Age = 3, Name = "Jim"}); PLa.Add(new Person { Age = 2, Name = "Jimmmy" }); PLa.Add(new Person { Age = 1, Name = "Jim" }); PLb.Add(new Person { Age = 1, Name = "Jim" }); PLb.Add(new Person { Age = 3, Name = "Jim" }); PLb.Add(new Person { Age = 2, Name = "Jimmmy" }); System.Diagnostics.Debug.WriteLine(ListSameIgnoreOrder(PLa, PLb)); } public bool ListSameIgnoreOrder(List PLa, List PLb) { if (PLa.Count != PLb.Count) return false; //PLa.Sort(); //PLb.Sort(); return Enumerable.SequenceEqual(PLa.OrderBy(s => s), PLb.OrderBy(s => s)); //for (int i = 0; i < PLa.Count; i++) //{ // System.Diagnostics.Debug.WriteLine( // PLa[i].Age.ToString() + " " + PLb[i].Age.ToString() + " " + // PLa[i].Name + " " + PLb[i].Name); // if (!PLa[i].Equals(PLb[i])) return false; //} //return true; } public class Person : object, IComparable { private int age = 0; private string name = string.Empty; private int hash; public int Age { get { return age; } set { if (age == value) return; age = value; CalcHash(); } } public string Name { get { return name; } set { if (name == value) return; name = value; CalcHash(); } } public override bool Equals(Object obj) { //Check for null and compare run-time types. if (obj == null || !(obj is Person)) return false; Person f = (Person)obj; if (f.Age != this.Age) return false; return (string.Compare(f.name, this.name) == 0); } private void CalcHash() { hash = Age.GetHashCode() ^ (Name ?? String.Empty).GetHashCode(); } public override int GetHashCode() { return hash; //return age ^ name.GetHashCode(); } public int CompareTo(object obj) { if (obj == null) return 1; Person otherPerson = obj as Person; if (otherPerson != null) { if (otherPerson.Age > this.Age) return -1; if (otherPerson.Age < this.Age) return 1; // compare all properties like above return string.Compare(otherPerson.name, this.name); } else throw new ArgumentException("Object is not a Person"); } public Person() { CalcHash(); } } 

这很有效。

 public bool EqualList(Dictionary a, Dictionary b) { if (a.Count == b.Count) { bool rs = false; foreach (var i in a) { if (b.ContainsKey(i.Key)) { rs = true; } else { rs = false; break; } } return rs; } else { return false; } 

用法:

 if(EqualList(List.ToDictionary(k => k.Key, k => k.Value), List.ToDictionary(k => k.Key, k => k.Value)){ }else{ }