又是一个比较列表的问题。
List<MyType> list1;
List<MyType> list2;
我需要检查它们是否拥有相同的元素,而不考虑它们在列表中的位置。每个对象可能会出现在列表中多次。是否有内置的函数可以检查这一点?如果我保证每个元素仅在列表中出现一次呢?编辑:大家谢谢你们的回答,但我忘记添加一些信息,每个元素的出现次数在两个列表中应该相同。
又是一个比较列表的问题。
List<MyType> list1;
List<MyType> list2;
我需要检查它们是否拥有相同的元素,而不考虑它们在列表中的位置。每个对象可能会出现在列表中多次。是否有内置的函数可以检查这一点?如果我保证每个元素仅在列表中出现一次呢?Enumerable.SequenceEqual(list1.OrderBy(t => t), list2.OrderBy(t => t))
这里有一个性能更好的解决方案(大约快了十倍),只需要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);
}
要处理任何数据类型作为键(例如,像Frank Tzanabetis指出的可空类型),您可以创建一个采用字典比较器的版本:
public static bool ScrambledEquals<T>(IEnumerable<T> list1, IEnumerable<T> list2, IEqualityComparer<T> comparer) {
var cnt = new Dictionary<T, int>(comparer);
...
SequenceEqual
作为扩展方法。但我应该指出,这需要T
是IComparable
,而ToLookup
版本只需要正确的GetHashCode
和Equals
实现。 - Anicnt[s]>0
。如果不是,您可以立即返回 false
- DixonDif (list1 == null && list2 == null) { return true; } if (list1 == null || list2 == null) { return false; }
这样可以避免空引用异常并保证代码正常运行。 - Jacob如果你不关心出现次数,我会这样处理。 使用哈希集比简单迭代更有效率。
var set1 = new HashSet<MyType>(list1);
var set2 = new HashSet<MyType>(list2);
return set1.SetEquals(set2);
这将需要您覆盖 .GetHashCode()
并在 MyType
上实现 IEquatable<MyType>
。HashSet<T>
还需要您实现 Equals
方法。项目将相互比较,不仅仅是哈希码的比较。 - GuffaEquals
。 - recursive这个问题本身存在歧义。以下陈述:
无论它们在列表中的位置如何,它们都具有相同的元素。每个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 [(A-B) Union (B-A)] is empty
var areEquivalent = !list1.Except(list2).Union( list2.Except(list1) ).Any();
使用集合操作(Intersect,Union,Except)比使用Contains等方法更有效率。在我看来,它也更好地表达了您查询的期望。
编辑:现在你已经澄清了你的问题,我可以说你想使用第一种形式——因为重复项很重要。这里有一个简单的例子来演示您可以获得所需的结果: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();
a = new[] {1,5,5}
和 b = new[] {1,1,5}
。这些集合没有完全相同的成员,但areEquivalent
被设置为true
。 - Remko Jansen{ 1,1,2,2,3,3 } != { 1,2,3,4,5,6 }
即使以相反的方向执行.Except(...)
也无法解决问题:{ 1,1,2,3 } != { 1,2,2,3 }
- Josh Gust除了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
list1.Distinct()
后。如果所有项都相同,而列表1是不同的,并且它们的长度相同,则列表2也必须是不同的。现在,{1,2}和{2,1}被认为是相同的,但{1,2,2}和{1,1,2}则不是。 - Brian GenisioContains()
的行为是正确的,但它可能导致 O(N<sup>2</sup>) 的性能问题。如果项目数量很大,则集合操作(Except、Intersect、Union)的性能要好得多。 - LBushkin这是一个稍微有难度的问题,我认为它可以简化为:“测试两个列表是否互为排列。”
我相信其他人提供的解决方案只能指示这两个列表是否包含相同的唯一元素。这是必要但不充分的测试,例如{1, 1, 2, 3}
不是{3, 3, 1, 2}
的排列,尽管它们的计数相等并且它们包含相同的不同元素。
我认为下面的方法可以解决问题,虽然不是最有效的:
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
),并且您想要一个符合该条件的第三个列表,则可以执行以下操作:var list3 = List1.Where(n => !List2.select(n1 => n1.Id).Contains(n.Id));
我使用这个方法)
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);