Bru*_*ira 226 c# comparison list equals
又一个列表比较问题.
List<MyType> list1;
List<MyType> list2;
Run Code Online (Sandbox Code Playgroud)
我需要检查它们是否具有相同的元素,无论它们在列表中的位置如何.每个MyType对象可能在列表中出现多次.是否有内置函数可以检查这个?如果我保证每个元素只在列表中出现一次怎么办?
编辑:伙计们感谢答案,但我忘了添加一些东西,每个元素的出现次数在两个列表上都应该相同.
Guf*_*ffa 284
如果你希望它们真的相同(即每个项目的相同项目和相同数量),我认为最简单的解决方案是在比较之前进行排序:
Enumerable.SequenceEqual(list1.OrderBy(t => t), list2.OrderBy(t => t))
Run Code Online (Sandbox Code Playgroud)
这是一个执行得更好(大约快十倍)的解决方案,只需要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);
}
Run Code Online (Sandbox Code Playgroud)
要将任何数据类型作为键处理(例如Frank Tzanabetis所指出的可空类型),您可以创建一个采用字典比较器的版本:
public static bool ScrambledEquals<T>(IEnumerable<T> list1, IEnumerable<T> list2, IEqualityComparer<T> comparer) {
var cnt = new Dictionary<T, int>(comparer);
...
Run Code Online (Sandbox Code Playgroud)
LBu*_*kin 46
如上所述,这个问题很暧昧.该声明:
......他们都有相同的元素,无论他们在列表中的位置如何.每个MyType对象可能在列表中出现多次.
并不表示您是否要确保两个列表具有相同的对象集或相同的不同集.
如果您想确保集合具有完全相同的成员集,而不管订单如何,您可以使用:
// lists should have same count of items, and set difference must be empty
var areEquivalent = (list1.Count == list2.Count) && !list1.Except(list2).Any();
Run Code Online (Sandbox Code Playgroud)
如果要确保两个集合具有相同的不同成员集(其中任何一个中的重复项都被忽略),您可以使用:
// check that [(A-B) Union (B-A)] is empty
var areEquivalent = !list1.Except(list2).Union( list2.Except(list1) ).Any();
Run Code Online (Sandbox Code Playgroud)
使用集合操作(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();
Run Code Online (Sandbox Code Playgroud)
rec*_*ive 40
如果你不关心事件的数量,我会像这样接近它.使用哈希集将比简单迭代提供更好的性能.
var set1 = new HashSet<MyType>(list1);
var set2 = new HashSet<MyType>(list2);
return set1.SetEquals(set2);
Run Code Online (Sandbox Code Playgroud)
这需要你已经覆盖.GetHashCode()和实施IEquatable<MyType>上MyType.
Tho*_*ken 12
除了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;
}
Run Code Online (Sandbox Code Playgroud)
认为这应该做你想要的:
list1.All(item => list2.Contains(item)) &&
list2.All(item => list1.Contains(item));
Run Code Online (Sandbox Code Playgroud)
如果你想要它是不同的,你可以将它改为:
list1.All(item => list2.Contains(item)) &&
list1.Distinct().Count() == list1.Count &&
list1.Count == list2.Count
Run Code Online (Sandbox Code Playgroud)
这是一个稍微困难的问题,我认为这个问题简化为:"测试两个列表是否是彼此的排列."
我相信其他人提供的解决方案仅表明2个列表是否包含相同的唯一元素.这是一个必要但不充分的测试,例如
{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());
}
Run Code Online (Sandbox Code Playgroud)