2013-04-24 13 views
9

Esiste un modo per fare una query LINQ2SQL fare qualcosa di simile a questo:Caso gruppo insensibile su più colonne

var result = source.GroupBy(a => new { a.Column1, a.Column2 }); 

o

var result = from s in source 
      group s by new { s.Column1, s.Column2 } into c 
      select new { Column1 = c.Key.Column1, Column2 = c.Key.Column2 }; 

ma con ignorando il caso del contenuto delle colonne raggruppate ?

+0

Questo non funziona? 'a => {Column1 = a.Column1.ToLower(), Column2 = a.Column2.ToLower()}' –

risposta

18

È possibile passare StringComparer.InvariantCultureIgnoreCase al metodo di estensione GroupBy.

var result = source.GroupBy(a => new { a.Column1, a.Column2 }, 
       StringComparer.InvariantCultureIgnoreCase); 

Oppure si può usare ToUpperInvariant su ogni campo come suggerito da Hamlet Hakobyan al commento. Raccomando ToUpperInvariant o ToUpper anziché ToLower o ToLowerInvariant perché è ottimizzato per scopi di confronto programmatico.

+6

Un 'StringComparer' non può confrontare istanze di tipi anonimi, solo stringhe. È necessaria una nuova implementazione di confronto (vedere la risposta di Bill B) –

+0

@DiegoMijelshon se 'Column1' e' Column2' sono tipo di 'string', quindi' GroupBy (a => a.Column1 + a.Column2, StringComparer.InvariantCultureIgnoreCase) ' dovrebbe funzionare – fubo

5

non ho potuto ottenere la soluzione di NaveenBhat a lavorare, ottenendo un errore di compilazione:

The type arguments for method 'System.Linq.Enumerable.GroupBy(System.Collections.Generic.IEnumerable, System.Func, System.Collections.Generic.IEqualityComparer)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

per farlo funzionare, l'ho trovato più semplice e più chiaro per definire una nuova classe dove riporre i miei colonne chiave (GroupKey) , quindi una classe separata che implementa IEqualityComparer (KeyComparer). Posso quindi chiamare

var result= source.GroupBy(r => new GroupKey(r), new KeyComparer()); 

classe Il KeyComparer non confrontare le corde con l'operatore di confronto InvariantCultureIgnoreCase, quindi complimenti a NaveenBhat per avermi nella giusta direzione.

versioni semplificate dei miei corsi:

private class GroupKey 
{ 
    public string Column1{ get; set; } 
    public string Column2{ get; set; } 

    public GroupKey(SourceObject r) { 
     this.Column1 = r.Column1; 
     this.Column2 = r.Column2; 
    } 
} 

private class KeyComparer: IEqualityComparer<GroupKey> 
{ 

    bool IEqualityComparer<GroupKey>.Equals(GroupKey x, GroupKey y) 
    { 
     if (!x.Column1.Equals(y.Column1,StringComparer.InvariantCultureIgnoreCase) return false; 
     if (!x.Column2.Equals(y.Column2,StringComparer.InvariantCultureIgnoreCase) return false; 
     return true; 
     //my actual code is more complex than this, more columns to compare 
     //and handles null strings, but you get the idea. 
    } 

    int IEqualityComparer<GroupKey>.GetHashCode(GroupKey obj) 
    { 
     return 0.GetHashCode() ; // forces calling Equals 
     //Note, it would be more efficient to do something like 
     //string hcode = Column1.ToLower() + Column2.ToLower(); 
     //return hcode.GetHashCode(); 
     //but my object is more complex than this simplified example 

    } 
} 
+0

Sei sicuro di non aver appena scritto 'StringComparison.InvariantCultureIgnoreCase' (che è un enum) invece di' StringComparer.InvariantCultureIgnoreCase' (che è una classe)? –

+0

Sei corretto, @dav_i, questa è la fonte dell'errore "Impossibile convertire da System.StringComparison" ... "che ho ricevuto. Tuttavia, anche se non faccio questo errore, è stato lanciato un errore di compilazione diverso. Ho aggiornato la mia risposta in modo da riflettere il problema riscontrato e le ragioni di questa soluzione. Grazie! –

1

ho avuto lo stesso problema raggruppamento dai valori di oggetti DataRow da una tabella, ma ho appena usato .ToString() sull'oggetto DataRow per superare il compilatore problema, ad es

MyTable.AsEnumerable().GroupBy(
    dataRow => dataRow["Value"].ToString(), 
    StringComparer.InvariantCultureIgnoreCase) 

invece di

MyTable.AsEnumerable().GroupBy(
    dataRow => dataRow["Value"], 
    StringComparer.InvariantCultureIgnoreCase)