在C#中比较数组

时间:2009-04-03 10:10:18

标签: c# arrays

我试图将两个数组相互比较。我尝试了这段代码并遇到了以下错误。

static bool ArraysEqual(Array a1, Array a2)
{
    if (a1 == a2)
        return true;

    if (a1 == null || a2 == null)
        return false;

    if (a1.Length != a2.Length)
        return false;

    IList list1 = a1, list2 = a2; //error CS0305: Using the generic type 'System.Collections.Generic.IList<T>' requires '1' type arguments
    for (int i = 0; i < a1.Length; i++)
    {
        if (!Object.Equals(list1[i], list2[i])) //error CS0021: Cannot apply indexing with [] to an expression of type 'IList'(x2)
            return false;
    }
    return true;
}

为什么我会收到错误?我选择了一种低技术解决方案并且做得很好,但我需要为每种类型复制/粘贴几次。

static bool ArraysEqual(byte[] a1, byte[] a2)
{
    if (a1 == a2)
        return true;

    if (a1 == null || a2 == null)
        return false;

    if (a1.Length != a2.Length)
        return false;

    for (int i = 0; i < a1.Length; i++)
    {
        if (a1[i] != a2[i])
            return false;
    }
    return true;
}

6 个答案:

答案 0 :(得分:154)

如果您提供LINQ并且不太关心性能,最简单的事情如下:

var arraysAreEqual = Enumerable.SequenceEqual(a1, a2);

事实上,可能值得用 Reflector ILSpy 检查SequenceEqual方法实际上做了什么,因为它可以很好地优化数组的特殊情况价值无论如何!

答案 1 :(得分:72)

“为什么我会收到错误?” - 可能,您在文件顶部没有“using System.Collections;” - 仅“using System.Collections.Generic;” - 但是,泛型可能更安全 - 请参阅下文:

static bool ArraysEqual<T>(T[] a1, T[] a2)
{
    if (ReferenceEquals(a1,a2))
        return true;

    if (a1 == null || a2 == null)
        return false;

    if (a1.Length != a2.Length)
        return false;

    EqualityComparer<T> comparer = EqualityComparer<T>.Default;
    for (int i = 0; i < a1.Length; i++)
    {
        if (!comparer.Equals(a1[i], a2[i])) return false;
    }
    return true;
}

答案 2 :(得分:12)

对于 .NET 4.0 及更高版本,您可以使用StructuralComparisons类型比较数组或元组中的元素:

object[] a1 = { "string", 123, true };
object[] a2 = { "string", 123, true };

Console.WriteLine (a1 == a2);        // False (because arrays is reference types)
Console.WriteLine (a1.Equals (a2));  // False (because arrays is reference types)

IStructuralEquatable se1 = a1;
//Next returns True
Console.WriteLine (se1.Equals (a2, StructuralComparisons.StructuralEqualityComparer)); 

答案 3 :(得分:6)

推荐SequenceEqual是好的,但认为(;;)循环可能比平时更快,这太天真了。

以下是反映的代码:

public static bool SequenceEqual<TSource>(this IEnumerable<TSource> first, 
    IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
{
    if (comparer == null)
    {
        comparer = EqualityComparer<TSource>.Default;
    }
    if (first == null)
    {
        throw Error.ArgumentNull("first");
    }
    if (second == null)
    {
        throw Error.ArgumentNull("second");
    }
    using (IEnumerator<TSource> enumerator = first.GetEnumerator())     
    using (IEnumerator<TSource> enumerator2 = second.GetEnumerator())
    {
        while (enumerator.MoveNext())
        {
            if (!enumerator2.MoveNext() || !comparer.Equals(enumerator.Current, enumerator2.Current))
            {
                return false;
            }
        }
        if (enumerator2.MoveNext())
        {
            return false;
        }
    }
    return true;
}

正如您所看到的,它使用了2个枚举器并触发了许多方法调用,这些调用严重降低了所有内容。它也根本不检查长度,所以在不好的情况下,它可能会变得非常慢。

将两个迭代器与漂亮的

进行比较
if (a1[i] != a2[i])

你会知道我对表现的意思。

它可用于性能确实不那么重要的情况,可能用于单元测试代码,或者用于很少调用方法中的一些短列表的情况。

答案 4 :(得分:2)

SequenceEqual可以更快。即在几乎所有时间的情况下,两个阵列的长度确实相同,并且不是同一个对象。

它仍然与OP的功能不同,因为它不会默默地比较空值。

答案 5 :(得分:0)

我知道这是一个古老的话题,但我认为这仍然是相关的,并希望分享一个阵列比较方法的实现,我觉得它在性能和优雅之间取得了适当的平衡。

static bool CollectionEquals<T>(ICollection<T> a, ICollection<T> b, IEqualityComparer<T> comparer = null)
{
    return ReferenceEquals(a, b) || a != null && b != null && a.Count == b.Count && a.SequenceEqual(b, comparer);
}

这里的想法是首先检查所有早期条件,然后再回到SequenceEqual。它还避免了额外的分支,而是依赖布尔短路来避免不必要的执行。我也觉得它看起来干净而且易于理解。

此外,通过使用ICollection作为参数,它不仅仅适用于数组。