可能重复:
Test whether two IEnumerable<T> have the same values with the same frequencies
我写了
更新 - 更正:
static bool HaveSameItems<T>(this IEnumerable<T> self, IEnumerable<T> other)
{
return !
(
other.Except(this).Any() ||
this.Except(other).Any()
);
}
有没有更短的方式?
我知道有SequenceEqual
但订单对我来说无关紧要。
答案 0 :(得分:6)
即使订单对您无关紧要,也不排除将SequenceEqual作为可行选项。
var lst1 = new [] { 2,2,2,2 };
var lst2 = new [] { 2,3,4,5 };
var lst3 = new [] { 5,4,3,2 };
//your current function which will return true
//when you compare lst1 and lst2, even though
//lst1 is just a subset of lst2 and is not actually equal
//as mentioned by Wim Coenen
(lst1.Count() == lst2.Count() &&
!lst1.Except(lst2).Any()); //incorrectly returns true
//this also only checks to see if one list is a subset of another
//also mentioned by Wim Coenen
lst1.Intersect(lst2).Any(); //incorrectly returns true
//So even if order doesn't matter, you can make it matter just for
//the equality check like so:
lst1.OrderBy(x => x).SequenceEqual(lst2.OrderBy(x => x)); //correctly returns false
lst3.OrderBy(x => x).SequenceEqual(lst2.OrderBy(x => x)); // correctly returns true
答案 1 :(得分:6)
这是一个O(n)
解决方案,只能遍历每个序列一次(实际上,它甚至可能不会完全走向第二个序列,它具有提前终止的可能性):
public static bool HaveSameItems<T>(IEnumerable<T> a, IEnumerable<T> b) {
var dictionary = a.GroupBy(x => x).ToDictionary(g => g.Key, g => g.Count());
foreach(var item in b) {
int value;
if (!dictionary.TryGetValue(item, out value)) {
return false;
}
if (value == 0) {
return false;
}
dictionary[item] -= 1;
}
return dictionary.All(x => x.Value == 0);
}
这个解决方案的一个缺点是它不会很好地与LINQ to SQL,EF,NHiberate等互操作。