C# LINQ:确定两个序列是否包含完全相同的元素
我需要确定两个集合是否包含完全相同的元素。顺序无关紧要 例如,这两个数组应视为相等:C# LINQ:确定两个序列是否包含完全相同的元素,c#,.net,linq,C#,.net,Linq,我需要确定两个集合是否包含完全相同的元素。顺序无关紧要 例如,这两个数组应视为相等: IEnumerable<int> data = new []{3, 5, 6, 9}; IEnumerable<int> otherData = new []{6, 5, 9, 3} IEnumerable data=new[]{3,5,6,9}; IEnumerable otherData=new[]{6,5,9,3} 一个集合不能包含任何不在另一个集合中的元素 是否可以使用内置的
IEnumerable<int> data = new []{3, 5, 6, 9};
IEnumerable<int> otherData = new []{6, 5, 9, 3}
IEnumerable data=new[]{3,5,6,9};
IEnumerable otherData=new[]{6,5,9,3}
一个集合不能包含任何不在另一个集合中的元素
是否可以使用内置的查询运算符来完成此操作?考虑到元素的数量可能从几个到几百个不等,实现它的最有效方法是什么
IEnumerable<int> data = new []{ 3,5,6,9 };
IEnumerable<int> otherData = new[] {6, 5, 9, 3};
if(data.All(x => otherData.Contains(x)))
{
//Code Goes Here
}
IEnumerable data=new[]{3,5,6,9};
IEnumerable otherData=new[]{6,5,9,3};
if(data.All(x=>otherData.Contains(x)))
{
//代码在这里
}
如果您可能有重复项(或者如果您想要一个对较长列表性能更好的解决方案),我会尝试以下方法:
static bool IsSame<T>(IEnumerable<T> set1, IEnumerable<T> set2)
{
if (set1 == null && set2 == null)
return true;
if (set1 == null || set2 == null)
return false;
List<T> list1 = set1.ToList();
List<T> list2 = set2.ToList();
if (list1.Count != list2.Count)
return false;
list1.Sort();
list2.Sort();
return list1.SequenceEqual(list2);
}
data.Intersect(其他数据)代码>,并检查长度是否相同
我建议对两者进行排序,并逐个元素进行比较
data.OrderBy(x => x).SequenceEqual(otherData.OrderBy(x => x))
我不确定OrderBy的实现速度有多快,但是如果它是一个O(n logn)排序,就像你期望的那样,那么整个算法也是O(n logn)
对于某些情况下的数据,您可以通过使用OrderBy的自定义实现来改进这一点,例如使用计数排序,对于O(n+k),k是值所在范围的大小。如果您希望将数组视为“集合”并忽略顺序和重复项,您可以使用:
var isEqual=newhashset(第一个)。SetEquals(第二个);
否则,您的最佳选择可能是以相同的方式对两个序列进行排序,并使用
SequenceEqual
对它们进行比较。首先检查两个数据集合是否具有相同数量的元素,然后检查一个集合中的所有元素是否都显示在另一个集合中
IEnumerable<int> data = new[] { 3, 5, 6, 9 };
IEnumerable<int> otherData = new[] { 6, 5, 9, 3 };
bool equals = data.Count() == otherData.Count() && data.All(x => otherData.Contains(x));
IEnumerable data=new[]{3,5,6,9};
IEnumerable otherData=new[]{6,5,9,3};
bool equals=data.Count()==otherData.Count()&&data.All(x=>otherData.Contains(x));
以下是另一种方法:
IEnumerable<int> data = new[] { 3, 5, 6, 9 };
IEnumerable<int> otherData = new[] { 6, 5, 9, 3 };
data = data.OrderBy(d => d);
otherData = otherData.OrderBy(d => d);
data.Zip(otherData, (x, y) => Tuple.Create(x, y)).All(d => d.Item1 == d.Item2);
IEnumerable data=new[]{3,5,6,9};
IEnumerable otherData=new[]{6,5,9,3};
data=data.OrderBy(d=>d);
otherData=otherData.OrderBy(d=>d);
data.Zip(otherData,(x,y)=>Tuple.Create(x,y)).All(d=>d.Item1==d.Item2);
<代码> >代码> {1,1,2} /代码>和<代码> {1,2} < /代码>“等效”序列。@ Mehrdad,是的,我希望那些被认为是相等的。通过“SET”,我想你是指所有元素都是唯一的。你可以使用。(而不是)(而不是计数)(那么它不会列举列表中的每一个项目。如果<代码>数据={1,2},其他数据={1,2,3} < /代码>?你也应该检查另一种方法。如果不按照Kobi的建议检查两种方法,这在我的场景中是行不通的。有几百个元素,我会担心这种方法的性能。@Kobi,既然你可以先检查哪一个更大,然后在复杂性上做例外的O(n²),为什么还要同时检查这两种方法呢。如果列表中的项目超过几十个,则会很危险。很简单,但这对于我的场景来说效果不够好。如果otherData
包含其他元素,则不会出现这种情况。我认为HashSet.SetEquals是我要找的方法:-)好答案--我忘记了SetEquals!如果您可能有重复,在排序之前,您可能应该先将序列复制到一个列表中并比较长度——这样可以在长度不同的情况下节省(昂贵的)排序或SequenceEqual()操作。@Justin Grant-我不懂。。。在比较长度之前,您需要删除重复项,这与排序一样昂贵。也许我有误解,但这不也会产生O(n^2)解决方案吗?HashSet-ctor被注释为O(n),SetEquals也被注释为O(n)(如果第一个和第二个使用相同的相等比较器)。@JoshGust使整个O(2n)=O(n)摊销而不是O(n^2)。这当然是假设一个好的散列函数。“data.Intersect(otherData),并检查长度是否相同”——您必须确保长度与其他两个相同sequences@Mark-在第一步中,你应该检查它们的长度是否相同,所以你应该没事。我同意,那写得不太好。(另外,谈论长尾……用2年的时间来获得评论)
)是的,这是真的。检查如此多的长度(因为它是IEnumerable)并不一定是可行的,尽管与仅从序列1创建哈希集并将其与序列2进行比较相比。Intersect基本上是这样做的。我喜欢这个方法的简单性,但它使用GetHashCode()进行元素比较。Zip将在到达任一列表的末尾时停止,这意味着{1,2,3,4}{1,2,3,4}将通过这个方法比较“equal”。您可以在Zip之前检查长度,但也可以使用SequenceEqual。对于常规数组,.Contains是O(N)和。All也是O(N),使其成为O(N^2)。如果数据集不是很小,则基于排序和/或集合的选项会更好。如果输入中允许重复,也不会给出正确答案。O(n log n)
比较非唯一序列的最佳复杂性也是如此吗?
IEnumerable<int> data = new[] { 3, 5, 6, 9 };
IEnumerable<int> otherData = new[] { 6, 5, 9, 3 };
bool equals = data.Count() == otherData.Count() && data.All(x => otherData.Contains(x));
IEnumerable<int> data = new[] { 3, 5, 6, 9 };
IEnumerable<int> otherData = new[] { 6, 5, 9, 3 };
data = data.OrderBy(d => d);
otherData = otherData.OrderBy(d => d);
data.Zip(otherData, (x, y) => Tuple.Create(x, y)).All(d => d.Item1 == d.Item2);