比较两个List <T>对象是否相等,忽略顺序

还有另一个列表比较问题。

List<MyType> list1; List<MyType> list2; 

我需要检查它们是否具有相同的元素,而不pipe它们在列表中的位置。 每个MyType对象可能在列表中多次出现。 有一个内置的函数来检查这个吗? 如果我保证每个元素只在列表中出现一次,该怎么办?

编辑:伙计们感谢您的答案,但我忘了添加一些东西,每个元素的出现次数应该在两个列表上是相同的。

如果你希望他们真的是平等的(即相同的项目和相同数量的每个项目),我认为最简单的解决scheme是比较之前进行sorting:

 Enumerable.SequenceEqual(list1.OrderBy(t => t), list2.OrderBy(t => t)) 

编辑:

这是一个更好的解决scheme(大约快十倍),只需要IEquatable ,而不是IComparable

 public static bool ScrambledEquals<T>(IEnumerable<T> list1, IEnumerable<T> list2) { var cnt = new Dictionary<T, int>(); foreach (T s in list1) { if (cnt.ContainsKey(s)) { cnt[s]++; } else { cnt.Add(s, 1); } } foreach (T s in list2) { if (cnt.ContainsKey(s)) { cnt[s]--; } else { return false; } } return cnt.Values.All(c => c == 0); } 

编辑2:

要处理任何数据types作为关键字(例如Frank Tzanabetis指出的可为空的types),可以创build一个版本,该版本为字典提供一个比较器 :

 public static bool ScrambledEquals<T>(IEnumerable<T> list1, IEnumerable<T> list2, IEqualityComparer<T> comparer) { var cnt = new Dictionary<T, int>(comparer); ... 

正如所写的,这个问题是模糊的。 该声明:

…他们都有相同的元素,不pipe他们在列表中的位置。 每个MyType对象可能在列表中多次出现。

并不表示是否要确保两个列表具有相同的一组对象或相同的不同组

如果您想确保集合中的成员集合完全相同 ,您可以使用:

 // lists should have same count of items, and set difference must be empty var areEquivalent = (list1.Count == list2.Count) && !list1.Except(list2).Any(); 

如果要确保两个集合具有相同的不同成员集(其中任何一个中的重复项都被忽略),则可以使用:

 // check that [(AB) Union (BA)] is empty var areEquivalent = !list1.Except(list2).Union( list2.Except(list1) ).Any(); 

使用set操作( IntersectUnionExcept )比使用Contains方法更有效率。 在我看来,它也更好地expression了你的查询的期望。

编辑:现在你已经澄清了你的问题,我可以说你想使用第一种forms – 因为重复的问题。 这里有一个简单的例子来certificate你得到了你想要的结果:

 var a = new[] {1, 2, 3, 4, 4, 3, 1, 1, 2}; var b = new[] { 4, 3, 2, 3, 1, 1, 1, 4, 2 }; // result below should be true, since the two sets are equivalent... var areEquivalent = (a.Count() == b.Count()) && !a.Except(b).Any(); 

如果你不关心事件的发生次数,我会这样处理。 使用哈希集合会给你比简单的迭代更好的性能。

 var set1 = new HashSet<MyType>(list1); var set2 = new HashSet<MyType>(list2); return set1.SetEquals(set2); 

这将要求您重写.GetHashCode()并在MyType上实现IEquatable<MyType>

除了Guffa的回答,你可以使用这个变种有一个更简短的符号。

 public static bool ScrambledEquals<T>(this IEnumerable<T> list1, IEnumerable<T> list2) { var deletedItems = list1.Except(list2).Any(); var newItems = list2.Except(list1).Any(); return !newItems && !deletedItems; } 

思考这个应该做你想做的事情:

 list1.All(item => list2.Contains(item)) && list2.All(item => list1.Contains(item)); 

如果你希望它是独特的,你可以改变它:

 list1.All(item => list2.Contains(item)) && list1.Distinct().Count() == list1.Count && list1.Count == list2.Count 

这是一个稍微困难的问题,我认为这个问题简化为:“testing两个列表是否相互排列。

我相信其他人提供的解决scheme只能说明2个列表是否包含相同的唯一元素。 这是一个必要但不足的testing,例如{1, 1, 2, 3} 1,1,2,3 {1, 1, 2, 3}不是{3, 3, 1, 2} 3,3,1,2 {1, 1, 2, 3}的排列,尽pipe它们的计数是相等的,它们包含相同的不同元素。

我相信这应该虽然不是最有效的,

 static bool ArePermutations<T>(IList<T> list1, IList<T> list2) { if(list1.Count != list2.Count) return false; var l1 = list1.ToLookup(t => t); var l2 = list2.ToLookup(t => t); return l1.Count == l2.Count && l1.All(group => l2.Contains(group.Key) && l2[group.Key].Count() == group.Count()); } 

这对我工作:
如果要比较两个对象列表取决于像ID这样的单个实体,并且您希望第三个列表匹配该条件,则可以执行以下操作:

 list3=List1.Where(n => !List2.select(n1 => n1.Id).Contains.(n.Id)); 

请参阅: MSDN – C#比较两个对象列表

我用这个方法)

 public delegate bool CompareValue<in T1, in T2>(T1 val1, T2 val2); public static bool CompareTwoArrays<T1, T2>(this IEnumerable<T1> array1, IEnumerable<T2> array2, CompareValue<T1, T2> compareValue) { return array1.Select(item1 => array2.Any(item2 => compareValue(item1, item2))).All(search => search) && array2.Select(item2 => array1.Any(item1 => compareValue(item1, item2))).All(search => search); } 

尝试这个!!!

使用以下代码,您可以比较一个或多个字段,以根据您的需要生成结果列表。 结果列表将只包含修改的项目。

 // veriables been used List<T> diffList = new List<T>(); List<T> gotResultList = new List<T>(); // compare First field within my MyList gotResultList = MyList1.Where(a => !MyList2.Any(a1 => a1.MyListTField1 == a.MyListTField1)).ToList().Except(gotResultList.Where(a => !MyList2.Any(a1 => a1.MyListTField1 == a.MyListTField1))).ToList(); // Generate result list diffList.AddRange(gotResultList); // compare Second field within my MyList gotResultList = MyList1.Where(a => !MyList2.Any(a1 => a1.MyListTField2 == a.MyListTField2)).ToList().Except(gotResultList.Where(a => !MyList2.Any(a1 => a1.MyListTField2 == a.MyListTField2))).ToList(); // Generate result list diffList.AddRange(gotResultList); MessageBox.Show(diffList.Count.ToString); 

回答

结合CountExceptAny这样的。 正如Bioukh所说的那样, Count首先要快。

 public static bool AreTheSameIgnoringOrder(List<string> x, List<string> y) { return x.Count() == y.Count() && !x.Except(y).Any() && !y.Except(x).Any(); // re: Servy's comment. } 

演示

这是一个演示小提琴。

 using System; using System.Collections.Generic; using System.Linq; public class Program { public static void Main() { var x = new List<string>() { "a", "b", "c"}; var result1 = AreTheSameIgnoringOrder(x, new List<string>() { "c", "b", "a"}); Console.WriteLine(result1); var result2 = AreTheSameIgnoringOrder(x, new List<string>() { "c", "b", "a", "b" }); Console.WriteLine(result2); } public static bool AreTheSameIgnoringOrder(List<string> x, List<string> y) { return x.Count() == y.Count() && !x.Except(y).Any() && !y.Except(x).Any(); } }