2012-05-17 19 views
18

Ho dato un'occhiata in giro e non riesco a trovare nulla per aiutare qui. Ho una classe:C# Linq intersecano/tranne che con una parte dell'oggetto

class ThisClass 
{ 
    private string a {get; set;} 
    private string b {get; set;} 
} 

Vorrei usare l'Intersect ed Except metodi di LINQ, cioè .:

private List<ThisClass> foo = new List<ThisClass>(); 
private List<ThisClass> bar = new List<ThisClass>(); 

Poi riempire le due liste separatamente. Mi piacerebbe fare, per esempio (e so che questo non è giusto, solo pseudocodice), quanto segue:

foo[a].Intersect(bar[a]); 

Come potrei fare questo?

Grazie per qualsiasi aiuto :)

+0

Cosa vuoi? Spiega a parole cosa vuoi da questa riga 'foo [a] .Intersect (bar [a]);'. –

risposta

25

Forse

// returns list of intersecting property 'a' values 
foo.Select(f => f.a).Intersect(bar.Select(b => b.a)); 

BTW proprietà a dovrebbero essere pubblici.

+0

Bello, semplice, fa proprio quello di cui ho bisogno. Grazie a te e a tutti i rispondenti. –

2
foo.Select(x=>x.a).Intersect(bar.Select(x=>x.a)) 
16

Se si desidera un elenco di una singola proprietà vuoi per intersecare poi tutte le altre soluzioni belle LINQ funzionano bene. MA! Se desideri intersecare un'intera classe e di conseguenza avere uno List<ThisClass> anziché List<string> dovrai scrivere il tuo comparatore di uguaglianza.

foo.Intersect(bar, new YourEqualityComparer()); 

stesso con Except.

public class YourEqualityComparer: IEqualityComparer<ThisClass> 
{ 

    #region IEqualityComparer<ThisClass> Members 


    public bool Equals(ThisClass x, ThisClass y) 
    { 
     //no null check here, you might want to do that, or correct that to compare just one part of your object 
     return x.a == y.a && x.b == y.b; 
    } 


    public int GetHashCode(ThisClass obj) 
    { 
     unchecked 
     { 
      var hash = 17; 
          //same here, if you only want to get a hashcode on a, remove the line with b 
      hash = hash * 23 + obj.a.GetHashCode(); 
      hash = hash * 23 + obj.b.GetHashCode(); 

      return hash;  
     } 
    } 

    #endregion 
} 
-2

È necessario creare IEqualityComparer. È possibile passare il metodo IEqualityComparer al metodo Intersect(). Questo ti aiuterà ad ottenere più facilmente List (che si interseca con la barra).

var intersectionList = foo.Intersect(bar, new ThisClassEqualityComparer()).ToList(); 


class ThisClassEqualityComparer : IEqualityComparer<ThisClass> 
{ 

    public bool Equals(ThisClass b1, ThisClass b2) 
    { 
     return b1.a == b2.a; 
    } 


    public int GetHashCode(Box bx) 
    { 
     // To ignore to compare hashcode, please consider this. 
     // I would like to force Equals() to be called 
     return 0; 
    } 

} 
+1

Non dovresti tornare '0' dal codice hash come questo. Questo ucciderà completamente le prestazioni. Dovresti invece usare il codice hash di 'a'. – Servy

0

Qual è esattamente l'effetto desiderato? Vuoi ottenere un elenco di stringhe composte da tutti gli a nelle tue classi o un elenco di ThisClass, quando due istanze ThisClass vengono identificate tramite valori univoci di a?

Se è il primo, le due risposte da @lazyberezovksy e @Tilak dovrebbero funzionare. Se si tratta di quest'ultimo, dovrete ignorare IEqualityComparer<ThisClass> o IEquatable<ThisClass> in modo che Intersect sa ciò che rende due istanze di ThisClass equivalente:

private class ThisClass : IEquatable<ThisClass> 
{ 
    private string a; 

    public bool Equals(ThisClass other) 
    { 
     return string.Equals(this.a, other.a); 
    } 
} 

allora si può chiamare:

var intersection = foo.Intersect(bar);  
+1

È sempre necessario sovrascrivere 'GetHashCode' quando si implementa' IEquatable'. Dal momento che non lo fai, questo non funzionerà. – Servy

3

Non sono sicuro del velocità di questo rispetto a intersecare e confrontare ma che dire:

//Intersect 
var inter = foo.Where(f => bar.Any(b => b.a == f.a)); 
//Except - values of foo not in bar 
var except = foo.Where(f => !bar.Any(b => b.a == f.a)); 
+3

Questo è un algoritmo O (n * m) mentre "Intersect" e "Except" sono entrambi "O (n + m)'. Questo ti rende molto peggio. Inoltre esegue iterazioni di 'bar' più volte, il che può essere un grosso problema in tutte le situazioni (potrebbe non produrre gli stessi risultati per ogni iterazione, potrebbe interrogare un database o preformare un calcolo costoso su ogni iterazione, potrebbe avere effetti collaterali causato quando iterato, ecc. – Servy

0

So che questo è vecchio ma non potresti È sufficiente sovrascrivere gli Equals & GetHashCode sulla classe stessa?

class ThisClass 
{ 
    public string a {get; set;} 
    private string b {get; set;} 

    public override bool Equals(object obj) 
    { 
    // If you only want to compare on a 
    ThisClass that = (ThisClass)obj; 
    return string.Equals(a, that.a/* optional: not case sensitive? */); 
    } 

    public override int GetHashCode() 
    { 
    return a.GetHashCode(); 
    } 
}