Comparando matrizes em c #

Eu estou tentando comparar duas matrizes entre si. Eu tentei este código e recebi os seguintes erros.

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' 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; } 

Por que recebo esse erro? Eu fui para uma solução de baixa tecnologia e fiz isso que funciona bem, mas eu preciso copiar / colar várias vezes para cada tipo.

 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; } 

Desde que você tenha LINQ disponível e não se importe muito com o desempenho, o mais fácil é o seguinte:

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

De fato, vale a pena verificar com o Reflector ou o ILSpy o que os methods SequenceEqual realmente fazem, já que ele pode otimizar para o caso especial de valores de array!

“Por que recebo esse erro?” – provavelmente, você não tem ” using System.Collections; ” no topo do arquivo – apenas ” using System.Collections.Generic; ” – entretanto, os genéricos provavelmente são mais seguros – veja abaixo:

 static bool ArraysEqual(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 comparer = EqualityComparer.Default; for (int i = 0; i < a1.Length; i++) { if (!comparer.Equals(a1[i], a2[i])) return false; } return true; } 

Para o .NET 4.0 e superior, você pode comparar elementos na matriz ou tuplas usando o tipo 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)); 

Recomendar SequenceEqual é ok, mas pensar que pode ser mais rápido que o normal para o loop (;;) é ​​muito ingênuo.

Aqui está o código refletido:

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

Como você pode ver, ele usa 2 enumeradores e aciona várias chamadas de método que reduzem seriamente a velocidade de execução. Também não verifica a duração, portanto, em casos ruins, pode ser ridiculamente mais lento.

Compare movendo dois iteradores com belas

 if (a1[i] != a2[i]) 

e você saberá o que quero dizer sobre desempenho.

Pode ser usado em casos em que o desempenho não é realmente tão crítico, talvez em código de teste de unidade, ou em casos de alguma lista pequena em methods raramente chamados.

SequenceEqual pode ser mais rápido. Ou seja, no caso em que quase todo o tempo, ambos os arrays têm realmente o mesmo comprimento e não são o mesmo object.

Ainda não é a mesma funcionalidade que a function do OP, pois não irá comparar silenciosamente os valores nulos.

Eu sei que este é um tópico antigo, mas eu acho que ainda é relevante, e gostaria de compartilhar uma implementação de um método de comparação de matriz que eu sinto o equilíbrio certo entre desempenho e elegância.

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

A ideia aqui é verificar primeiro todas as condições iniciais, depois recorrer ao SequenceEqual . Ele também evita ramificações extras e, em vez disso, depende de um curto-circuito booleano para evitar a execução desnecessária. Eu também sinto que parece limpo e é fácil de entender.

Além disso, usando ICollection para os parâmetros, ele funcionará com mais do que apenas matrizes.