2011-09-02 15 views
145

Questo è abbastanza semplice, ma io sono in perdita: Dato questo tipo di set di dati:LINQ con groupby e contare

UserInfo(name, metric, day, other_metric) 

e questo insieme 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 

I' mi piacerebbe 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 insieme che ci si finisce 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 .... alcun aiuto ??

Modifica POST: non sono mai riuscito a ottenere le risposte postate perché hanno sempre restituito 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 dato un insieme ordinato di record con 'metriche' e il numero di utenti associati a ciascuno. Sono chiaramente nuovo a LINQ in generale e al mio occhio inesperto questo approccio sembra molto simile al puro approccio LINQ, ma mi ha dato una risposta diversa.

+0

Sì, sì, ma la spiegazione di jimmy mi ha aiutato di più. Tuttavia non sono mai riuscito a far funzionare il suo esempio, ma mi ha portato in una nuova direzione. – Gio

risposta

254

Dopo aver chiamato GroupBy, si ottiene una serie di gruppi IEnumerable<Grouping>, dove ogni raggruppamento si espone il Key utilizzato per creare il gruppo e anche è un IEnumerable<T> di qualsiasi articoli sono nel set di dati originale. Devi solo chiamare Count() in 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); 
} 


Questo è stato un brillante rapida risposta, ma sto avendo un po 'un problema con la prima linea, in particolare "data.groupby (info => info.metric)"

sto assumendo si dispone già di un elenco/array di alcuni class che assomiglia

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

Quando si esegue data.GroupBy(x => x.metric), significa "per ogni elemento x nel IEnumerable definito da data, il calcolo è .metric, quindi raggruppare tutti gli elementi con la stessa metrica in un Grouping e restituire un IEnumerable di tutti i gruppi che ne derivano. Dato il 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 

che 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] 
+0

Questa è stata una risposta brillante ma ho un po 'di problemi con la prima riga, in particolare "data.groupby (info => info.metric)". Chiaramente, "data" è il set di dati attuale, ma cosa rappresenta "info.metric"? la definizione della classe? – Gio

+0

"info.metric" sarebbe il campo/proprietà metrica nella classe UserInfo che hai menzionato nella tua domanda. –

+1

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

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

Supponendo userInfoList è un List<UserInfo>: La funzione

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

lambda per GroupBy(), n => n.metric mea ns che otterrà il campo metric da ogni oggetto UserInfo rilevato.Il tipo di n dipende dal contesto, nella prima occorrenza è di tipo UserInfo, poiché l'elenco contiene oggetti UserInfo. Nella seconda occorrenza, n è di tipo Grouping, perché ora è un elenco di oggetti Grouping.

Grouping s hanno metodi di estensione come .Count(), .Key() e praticamente qualsiasi altra cosa che ci si aspetterebbe. Proprio come si controlla su un string, è possibile controllare .Count() su un gruppo.