2016-03-27 14 views
5

E 'possibile utilizzare se non con due liste di array int, in questo modo:utilizzando LINQ Tranne che con due liste di array int

List<int[]> a = new List<int[]>(){ new int[]{3,4,5}, new int[]{7,8,9}, new int[]{10,11,12} }; 

List<int[]> b = new List<int[]>(){ new int[]{6,7,9}, new int[]{3,4,5}, new int[]{10,41,12} }; 

var c = a.Except(b); 

e exepecting {3,4,5} essere assente del enumerabile c? Certo che ho provato e questo non funziona. Esiste una soluzione tanto efficiente quanto Tranne? O ancora meglio, più veloce?

risposta

6

In .NET, gli array sono uguali a un altro se sono esattamente lo stesso oggetto matrice. Così due matrici distinte che hanno gli stessi contenuti non sono considerati uguali:

int[] x = new int[] { 1, 2 }; 
int[] y = new int[] { 1, 2 }; 
Console.WriteLine(x == y); // false 

Al fine di verificare l'uguaglianza in base al contenuto, è possibile utilizzare Enumerable.SequenceEqual:

Console.WriteLine(x.SequenceEqual(y)); // true 

Certo che non lo fa ti aiuta direttamente quando provi ad usare Enumerable.Except, poiché per impostazione predefinita userà il comparatore di uguaglianza di default che controlla solo l'uguaglianza (e dal momento che ogni array è diverso da ogni altro array tranne se stesso ...).

Quindi la soluzione sarebbe use the other overload e fornire un numero personalizzato IEqualityComparer che confronta gli array in base al loro contenuto.

public class IntArrayEqualityComparer : IEqualityComparer<int[]> 
{ 
    public bool Equals(int[] a, int[] b) 
    { 
     return a.SequenceEqual(b); 
    } 

    public int GetHashCode(int[] a) 
    { 
     return a.Sum(); 
    } 
} 

Purtroppo, proprio delegando ad SequenceEqual non è sufficiente. Dobbiamo anche fornire un'implementazione GetHashCode affinché funzioni. Come soluzione semplice, possiamo usare qui la somma dei numeri nell'array. Di solito, vorremmo fornire una forte funzione di hash, che dice molto sui contenuti, ma dal momento che stiamo usando questa funzione di hash per la chiamata Except, possiamo usare qualcosa di semplice qui. (In generale, ci sarebbe anche voler evitare di creare un valore hash da un oggetto mutabile)

E quando usando quel confronto di uguaglianza, abbiamo correttamente filtrare gli array duplicati:

var c = a.Except(b, new IntArrayEqualityComparer()); 
+0

ringrazio per la spiegazione e per la soluzione di lavoro! – Albertino

5

Questo perché EqualityComparer predefinito per int matrice restituisce false per per gli array con gli stessi valori:

int[] a1 = { 1, 2, 3 }; 
int[] a2 = { 1, 2, 3 }; 
var ec = EqualityComparer<int[]>.Default; 
Console.WriteLine(ec.Equals(a1, a2));//result is false 

È possibile risolvere il problema mediante l'attuazione di vostra EqualityComparer e passando la sua istanza di Salvo il metodo (see documentation).

È inoltre possibile leggere il confronto degli array in C# here.

+0

Grazie per i suggerimenti – Albertino

Problemi correlati