C#:比较两个IEnumerables的内容

时间:2009-03-10 13:52:19

标签: c# linq

是否有内置的linq方法,我可以用它来确定两个序列是否包含相同的项目,而不考虑订单?

例如:

{1, 2, 3} == {2, 1, 3}
{1, 2, 3} != {2, 1, 3, 4}
{1, 2, 3} != {1, 2, 4}

你有SequenceEquals,但是我必须先对两个序列进行排序,不是吗?

9 个答案:

答案 0 :(得分:37)

有很多方法。假设A和B是IEnumerable。

!A.Except(B).Any() && !B.Except(A).Any()
A.Count() == B.Count() && A.Intersect(B).Count() == B.Count()
etc

答案 1 :(得分:9)

有两个IEnumerables(A和B):

bool equal = (A.Count() == B.Count() && (!A.Except(B).Any() || !B.Except(A).Any()))

我认为这比Except(A).Count更好,因为不会评估整个Excep。只要在“除外”中找到一个元素,它就会停止。使用Count,可以评估整个Except。 除此之外,我们可以避免对这些代价高昂的评估,除非首先检查Count属性。如果计数不相等,那么我们检查Excepts。

答案 2 :(得分:4)

如果您不关心重复项(即您认为{1, 2, 3}等于{1, 2, 3, 2}),那么:

new HashSet<int>(A).SetEquals(B)

(或者任何类型的元素类型而不是int)。

否则:

public static bool SequenceEqualUnordered<T>(IEnumerable<T> first, IEnumerable<T> second)
{
    if (first == null)
        return second == null; // or throw if that's more appropriate to your use.
    if (second == null)
        return false;   // likewise.
    var dict = new Dictionary<T, int>(); // You could provide a IEqualityComparer<T> here if desired.
    foreach(T element in first)
    {
        int count;
        dict.TryGetValue(element, out count);
        dict[element] = count + 1;
    }
    foreach(T element in second)
    {
        int count;
        if (!dict.TryGetValue(element, out count))
            return false;
        else if (--count == 0)
            dict.Remove(element);
        else
            dict[element] = count;
    }
    return dict.Count == 0;
}

保持第一个序列中每个元素的计数,然后检查第二个序列。你在第二个序列中有一个太多的那一刻你可以返回false,否则如果你在相关词典中没有任何东西它们是相等的,或者如果剩下任何元素则为false。

使用OrderBy()后跟O(n)比较的两个O(n log n)种类,而不是O(n)操作构建一组计数,并且是O(n检查它。

答案 3 :(得分:3)

尝试使用HashSet类:

var enumA = new[] { 1, 2, 3, 4 };
var enumB = new[] { 4, 3, 1, 2 };

var hashSet = new HashSet<int>(enumA);
hashSet.SymmetricExceptWith(enumB);
Console.WriteLine(hashSet.Count == 0); //true => equal

但是,如果值不同,那只能正常工作。

例如

var enumA = new[] { 1, 1, 1, 2 };
var enumB = new[] { 1, 2, 2, 2 };

也被认为与上述方法“相同”。

答案 4 :(得分:1)

我认为订购序列是实现这一目标的最快方法。

答案 5 :(得分:1)

我这样做是为了将新项目合并到一个没有重复的集合中,  它需要两个集合并返回所有没有重复的项目

List<Campaign> nonMatching = (from n in newCampaigns 
where !(from e in Existing select e.Id).Contains<int>(n.Id) 
select n).ToList<Campaign>();

现在删除!对于包含语句

List<Campaign> nonMatching = (from n in newCampaigns 
where (from e in Existing select e.Id).Contains<int>(n.Id) 
select n).ToList<Campaign>();

它将返回重复项

答案 6 :(得分:0)

如果您真的只是在测试是否有重复项,那么leppie的建议应该有效:

if (A.Except(B).Count == 0 && B.Except(A).Count == 0) {...}

但是如果你只需要一个没有重复的IEnumerable:

var result = A.Union(B).Distinct();

答案 7 :(得分:0)

通过示例,您可以将IEnumerable都设置为List类型,然后使用SequenceEqual作为以下示例:

var first = Enumerable.Range(1, 3);
var second = Enumerable.Range(1, 3);
var areTheyEqual = first.ToList().SequenceEqual(second.ToList());
if (areTheyEqual)
{ /* do something... */}

答案 8 :(得分:0)

为了比较两个对象中的数据,我只使用了

A.Except(B).Any() || B.Except(A).Any()