2011-09-02 18 views
145

Esto es bastante simple, pero estoy en una pérdida: Teniendo en cuenta este tipo de conjunto de datos:LINQ con GroupBy y contar

UserInfo(name, metric, day, other_metric) 

y este conjunto de datos de ejemplo:

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' Me gusta recuperar una tabla que enumera las medidas en orden (0,1,2,3 ..) con el número total de veces que se produce el recuento. Así que a partir de este conjunto que terminarías con:

0 3  
1 2  
2 2  
3 1 

estoy luchando con la sintaxis de LINQ, pero estoy atascado en donde poner un GroupBy y contar .... cualquier ayuda ??

POST Editar: Nunca pude obtener las respuestas publicadas para trabajar, ya que siempre devolvieron un registro con el número de cuentas diferentes. Sin embargo, era capaz de armar un ejemplo LINQ a SQL que hizo el trabajo:

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

Este resultado me dio un conjunto ordenado de registros con 'indicadores' y el número de usuarios asociados con cada uno. Soy claramente nuevo en LINQ en general y para mi ojo no entrenado este enfoque parece muy similar al enfoque puro de LINQ pero me dio una respuesta diferente.

+0

Sí, lo tengo, pero la explicación de jimmy me ayudó más aún. Sin embargo, nunca pude poner su ejemplo a trabajar, pero sí me condujo en una nueva dirección. – Gio

Respuesta

254

Después de llamar GroupBy, se obtiene una serie de grupos, donde cada IEnumerable<Grouping> agrupándose expone los Key utilizado para crear el grupo y también es un IEnumerable<T> de cualquier artículos están en el conjunto de datos original. Solo tiene que llamar al Count() en esa Agrupación para obtener el subtotal.

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); 
} 


Esta fue una respuesta rápida brillantemente pero estoy teniendo un poco de un problema con la primera línea, específicamente "data.groupby (info => info.metric)"

estoy asumiendo que ya tiene una lista/arreglo de algunos class que se parece a

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

Al hacer data.GroupBy(x => x.metric), que significa "para cada elemento x en el IEnumerable definido por data, el cálculo es .metric, a continuación, agrupar todos los elementos con la misma métrica en un Grouping y devolver una IEnumerable de todos los grupos resultantes. Teniendo en cuenta el conjunto de datos de ejemplo de

<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 

que daría lugar a los siguientes resultados después de la 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

Esta fue una respuesta brillantemente rápida, pero estoy teniendo un problema con la primera línea, específicamente "data.groupby (info => info.metric)". En realidad, 'datos' es el conjunto de datos actual, pero ¿qué representa 'info.metric'? la definición de clase? – Gio

+0

"info.metric" sería la propiedad/campo métrica en la clase UserInfo que mencionó en su pregunta. –

+1

Gracias, pero creo que esto realmente me da un valor único, es decir, el número total de recuentos de métricas diferentes. En este ejemplo, obtengo "métricas 4" que me indica cuántos conteos diferentes tengo. – Gio

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

Suponiendo userInfoList es un List<UserInfo>: La función lambda

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

para GroupBy(), n => n.metric mea ns que obtendrá el campo metric de cada objeto UserInfo encontrado.El tipo de n depende del contexto, en la primera aparición es del tipo UserInfo, porque la lista contiene UserInfo objetos. En la segunda aparición n es de tipo Grouping, porque ahora es una lista de objetos Grouping.

Grouping s tienen métodos de extensión como .Count(), .Key() y casi cualquier otra cosa que esperas. Del mismo modo que consultaría .Lenght en un string, puede marcar .Count() en un grupo.