Obtendo o “diff” entre duas matrizes em c #?

Digamos que eu tenha esses dois arrays:

var array1 = new[] {"A", "B", "C"}; var array2 = new[] {"A", "C", "D"}; 

Eu gostaria de obter as diferenças entre os dois. Eu sei que eu poderia escrever isso em apenas algumas linhas de código, mas quero ter certeza de que não estou perdendo um recurso de linguagem embutido ou um método de extensão LINQ.

Idealmente, acabaria com os três resultados a seguir:

  • Itens que não estão no array1, mas estão no array2 (“D”)
  • Itens não em array2, mas estão em array1 (“B”)
  • Itens que estão em ambos

Desde já, obrigado!

Se você tem LINQ disponível para você, você pode usar Except e Distinct . Os conjuntos que você pediu na pergunta são respectivamente:

 - array2.Except(array1) - array1.Except(array2) - array1.Intersect(array2) 

das amostras do MSDN 101 LINQ ….

 public void Linq52() { int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 }; int[] numbersB = { 1, 3, 5, 7, 8 }; IEnumerable aOnlyNumbers = numbersA.Except(numbersB); Console.WriteLine("Numbers in first array but not second array:"); foreach (var n in aOnlyNumbers) { Console.WriteLine(n); } } 

Aqui estão os benchmarks dos methods de extensão do LINQ. Os resultados foram obtidos durante o desenvolvimento de um programa real.

Os testes: 2 listas (lst1 e lst2) cada um aproximadamente 250000 objects. Cada object (class Key) contém uma string e um inteiro. A segunda lista contém principalmente as mesmas inputs que a primeira, mas algumas novas inputs são adicionadas e algumas são removidas.

Eu testei o método de extensão Exceto.

var exceto = lst2.Except (lst1);

Listar lst = except.ToList ();

Essas duas linhas produziram uma lista de 600 itens de “novas adições”. Eu cronometrei usando o object StopWatch. A velocidade é surpreendente: 220 ms . O computador que usei não é de forma alguma um “Gonzales veloz”. Core 2 Duo T7700 – 2.4GHz.

Nota:

Aqui está a class Key, que implementa IEquatable i-face.

 public class Key : IEquatable { public int Index { get; private set; } public string Name { get; private set; } public Key(string keyName, int sdIndex) { this.Name = keyName; this.Index = sdIndex; } // IEquatable implementation public bool Equals(Key other) { //Check whether the compared object is null. if (Object.ReferenceEquals(other, null)) return false; //Check whether the compared object references the same data. if (Object.ReferenceEquals(this, other)) return true; //Check whether the products' properties are equal. return Index.Equals(other.Index) && Name.Equals(other.Name); } // If Equals() returns true for a pair of objects // then GetHashCode() must return the same value for these objects. public override int GetHashCode() { //Get hash code for the name field if it is not null. int hashKeyName = Name == null ? 0 : Name.GetHashCode(); //Get hash code for the index field. int hashKeyIndex = Index.GetHashCode(); //Calculate the hash code for the Key. return hashKeyName ^ hashKeyIndex; } } 

Eu tive que fazer coisas semelhantes a isso com conjuntos muito grandes de dados. Se você está lidando com alguns milhares ou mais, use o material do Linq já que é muito mais claro. Mas se você sabe que suas matrizes são pré-classificadas, executar uma mesclagem como essa pode fazer isso significativamente mais rápido, já que ela apenas faz uma passagem pelos dados e não precisa alocar tanta memory quanto a versão do Linq.

 int iA = 0; int iB = 0; List inA = new List(); List inB = new List(); List inBoth = new List(); while (iA < numbersA.Length && iB < numbersB.Length) { if (numbersA[iA] < numbersB[iB]) { inA.Add(numbersA[iA++]); } else if (numbersA[iA] == numbersB[iB]) { inBoth.Add(numbersA[iA++]); ++iB; } else { inB.Add(numbersB[iB++]); } } while (iA < numbersA.Length) { inA.Add(numbersA[iA++]); } while (iB < numbersB.Length) { inB.Add(numbersB[iB++]); } 

Novamente, isso é realmente necessário apenas se você estiver lidando com centenas de milhares de valores.

Outra solução seria como abaixo também

 int[] arr1 = new int[] { 45, 26, 99, 55, 36 }; int[] arr2 = new int[] { 45, 26, 99, 20, 36 }; var res = arr1.Union(arr2).Except(arr1.Intersect(arr2));