在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; }
为什么我得到这个错误? 我去了一个低科技的解决scheme,并做了这个工作正常,但我需要复制/粘贴几次,每种types。
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; }
假如你有LINQ可用并且不关心性能,最简单的事情是:
var arraysAreEqual = Enumerable.SequenceEqual(a1, a2);
实际上,使用Reflector或者ILSpy来检查SequenceEqual
方法实际上可能是值得的,因为无论如何它都可以优化数组值的特殊情况!
“为什么我得到那个错误?” – 可能,在文件的顶部没有“ using System.Collections;
” – 只有“ using System.Collections.Generic;
” – 但是,generics可能更安全 – 请参阅下面的内容:
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; }
对于.NET 4.0及更高版本,可以使用StructuralComparisonstypes比较数组或元组中的元素:
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));
推荐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])
你会知道我的意思是关于表演。
它可以用在性能不是那么重要的情况下,可能在unit testing代码中,或者在很less被调用的方法中使用一些简短列表的情况下。
SequenceEqual可以更快。 即在几乎所有的时候,两个arrays的长度确实相同而且不是同一个对象。
它仍然不是OP的function,因为它不会静默地比较空值。
我知道这是一个老话题,但我认为它仍然是相关的,并希望分享一个数组比较方法的实现,我觉得在性能和优雅之间取得了正确的平衡。
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
作为参数,它将不仅仅用于数组。