LINQ:确定两个序列是否包含完全相同的元素

dri*_*iis 66 .net c# linq

我需要确定两个集合是否包含完全相同的元素.排序无关紧要.

例如,这两个数组应该被认为是相等的:

IEnumerable<int> data = new []{3, 5, 6, 9};
IEnumerable<int> otherData = new []{6, 5, 9, 3}
Run Code Online (Sandbox Code Playgroud)

一组不能包含任何不在另一组中的元素.

可以使用内置查询运算符完成吗?考虑到元素的数量可以从几个到几百个,那么实现它的最有效方法是什么?

Meh*_*ari 113

如果要将数组视为"集合"并忽略顺序和重复项,则可以使用以下HashSet<T>.SetEquals方法:

var isEqual = new HashSet<int>(first).SetEquals(second);
Run Code Online (Sandbox Code Playgroud)

否则,您最好的选择可能是以相同的方式对两个序列进行排序并使用SequenceEqual它们进行比较.

  • @Justin Grant - 我没有关注......你需要在比较长度之前删除重复项,这和排序一样昂贵. (2认同)

Jor*_*ren 45

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

data.OrderBy(x => x).SequenceEqual(otherData.OrderBy(x => x))
Run Code Online (Sandbox Code Playgroud)

我不确定实现的速度有多快OrderBy,但如果它是一个O(n log n)排序,就像你期望总算法也是O(n log n)一样.

对于某些数据情况,您可以通过使用OrderBy的自定义实现来改进这一点,例如对O(n + k)使用计数排序,其中k是值所在范围的大小.


Jus*_*ant 5

如果您可能有重复项(或者如果您想要一个对更长列表表现更好的解决方案),我会尝试这样的事情:

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);
}
Run Code Online (Sandbox Code Playgroud)

更新:哎呀,你们是对的——下面的 except() 解决方案需要在过马路之前看两边。对于较长的列表,它的性能很差。忽略下面的建议!:-)

这是一种简单的方法。请注意,这假设列表没有重复项。

bool same = data.Except (otherData).Count() == 0;
Run Code Online (Sandbox Code Playgroud)

  • 如果`data = {1,2}, otherData = {1,2,3}` 会怎样?您还应该反过来检查。 (4认同)
  • 您可以使用 .Any() 而不是 Count() - 那么它不会枚举列表中的每个项目。 (3认同)