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(其他数据),并检查长度是否相同
  • 或者,simpt对集合进行排序,并遍历它们

  • 我建议对两者进行排序,并逐个元素进行比较

    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);