LINQ con groupby e count


221

Questo è piuttosto semplice, ma sono perplesso: dato questo tipo di set di dati:

UserInfo(name, metric, day, other_metric)

e questo set di dati di esempio:

joe  1 01/01/2011 5
jane 0 01/02/2011 9
john 2 01/03/2011 0
jim  3 01/04/2011 1
jean 1 01/05/2011 3
jill 2 01/06/2011 5
jeb  0 01/07/2011 3
jenn 0 01/08/2011 7

Vorrei recuperare una tabella che elenca le metriche in ordine (0,1,2,3 ..) con il numero totale di volte in cui si verifica il conteggio. Quindi da questo set finiresti con:

0 3    
1 2    
2 2    
3 1

Sono alle prese con la sintassi LINQ ma sono bloccato su dove mettere un groupby e contare .... qualche aiuto ??

Modifica POST: non sono mai stato in grado di far funzionare le risposte pubblicate in quanto restituivano sempre un record con il numero di conteggi diversi. Tuttavia sono stato in grado di mettere insieme un esempio LINQ to SQL che ha funzionato:

        var pl = from r in info
                 orderby r.metric    
                 group r by r.metric into grp
                 select new { key = grp.Key, cnt = grp.Count()};

Questo risultato mi ha fornito un set ordinato di record con "metriche" e il numero di utenti associati a ciascuno. Sono chiaramente nuovo di LINQ in generale e al mio occhio non allenato questo approccio sembra molto simile al puro approccio LINQ ma mi ha dato una risposta diversa.


Sì, ma la spiegazione di Jimmy mi ha aiutato di più. Tuttavia non sono mai stato in grado di far funzionare il suo esempio, ma mi ha portato in una nuova direzione.
Gio

@Jimmy ha utilizzato la sintassi funzionale per le espressioni LINQ anziché la sintassi di query LINQ standard, inoltre ha deciso di mostrare l'esecuzione immediata di tali funzioni anziché il formato di esecuzione ritardata. Per una persona nuova che sarebbe fonte di confusione. Non so perché l'abbia fatto.
Richard Robertson,

Risposte:


395

Dopo aver chiamato GroupBy, si ottiene una serie di gruppi IEnumerable<Grouping>, in cui ogni gruppo stesso espone l' Keyusato per creare il gruppo ed è anche uno IEnumerable<T>degli elementi presenti nel set di dati originale. Devi solo chiamare Count()quel raggruppamento per ottenere il totale parziale.

foreach(var line in data.GroupBy(info => info.metric)
                        .Select(group => new { 
                             Metric = group.Key, 
                             Count = group.Count() 
                        })
                        .OrderBy(x => x.Metric)
{
     Console.WriteLine("{0} {1}", line.Metric, line.Count);
}


Questa è stata una risposta brillantemente veloce ma sto avendo un po 'di problemi con la prima riga, in particolare "data.groupby (info => info.metric)"

Suppongo che tu abbia già un elenco / matrice di alcuni classche assomiglia

class UserInfo {
    string name;
    int metric;
    ..etc..
} 
...
List<UserInfo> data = ..... ;

Quando lo fai data.GroupBy(x => x.metric), significa "per ogni elemento xin IEnumerable definito da data, calcola .metric, quindi raggruppa tutti gli elementi con la stessa metrica in a Groupinge restituisci uno IEnumerabledi tutti i gruppi risultanti. Dato il tuo set di dati di esempio di

    <DATA>           | Grouping Key (x=>x.metric) |
joe  1 01/01/2011 5  | 1
jane 0 01/02/2011 9  | 0
john 2 01/03/2011 0  | 2
jim  3 01/04/2011 1  | 3
jean 1 01/05/2011 3  | 1
jill 2 01/06/2011 5  | 2
jeb  0 01/07/2011 3  | 0
jenn 0 01/08/2011 7  | 0

comporterebbe il seguente risultato dopo il groupby:

(Group 1): [joe  1 01/01/2011 5, jean 1 01/05/2011 3]
(Group 0): [jane 0 01/02/2011 9, jeb  0 01/07/2011 3, jenn 0 01/08/2011 7]
(Group 2): [john 2 01/03/2011 0, jill 2 01/06/2011 5]
(Group 3): [jim  3 01/04/2011 1]

Questa è stata una risposta brillantemente veloce ma sto avendo un po 'di problemi con la prima riga, in particolare "data.groupby (info => info.metric)". Chiaramente 'data' è attualmente il set di dati ma cosa rappresenta 'info.metric'? la definizione di classe?
Gio

"info.metric" sarebbe la proprietà / campo della metrica nella classe UserInfo menzionata nella domanda.
lee-m,

1
Grazie capito ma in realtà questo sembra darmi un singolo valore - vale a dire il numero totale di conteggi metrici diversi. In questo esempio ottengo "metriche 4" che mi indicano quanti conteggi diversi ho.
Gio

1
Wow. Hai completamente spiegato il raggruppamento !! Solo questo è valso la pena post .... otterrò il risultato "metriche 4" ma grazie!
Gio

4
L'inizio di questa risposta, "dopo aver chiamato GroupBy, si ottiene una serie di gruppi IEnumerable <gruppo>, in cui ogni gruppo stesso espone la chiave utilizzata per creare il gruppo ed è anche un IEnumerable <T> di tutti gli elementi nei dati originali set ", è la spiegazione più chiara di LINQ GroupDa che ho ancora letto, grazie.
Silente,

48

Supponendo che userInfoListsia un List<UserInfo>:

        var groups = userInfoList
            .GroupBy(n => n.metric)
            .Select(n => new
            {
                MetricName = n.Key,
                MetricCount = n.Count()
            }
            )
            .OrderBy(n => n.MetricName);

La funzione lambda per GroupBy(), n => n.metricsignifica che otterrà campo metricda ogni UserInfooggetto incontrato. Il tipo di ndipende dal contesto, nella prima occorrenza è di tipo UserInfo, poiché l'elenco contiene UserInfooggetti. Nella seconda occorrenza nè di tipo Grouping, perché ora è un elenco di Groupingoggetti.

Groupings hanno metodi di estensione, come .Count(), .Key()e praticamente qualsiasi altra cosa che ci si aspetterebbe. Proprio come faresti .Lenghtcon un string, puoi controllare .Count()un gruppo.


23
userInfos.GroupBy(userInfo => userInfo.metric)
        .OrderBy(group => group.Key)
        .Select(group => Tuple.Create(group.Key, group.Count()));

1
piccolo errore di battitura -> group.keyin Seleziona (...) deve esseregroup.Key
Jan
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.