我试图将两个数组相互比较。我尝试了这段代码并遇到了以下错误。
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;
}
答案 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
作为参数,它不仅仅适用于数组。