LINQ avec groupby et count


221

C'est assez simple, mais je suis à perte: étant donné ce type de jeu de données:

UserInfo(name, metric, day, other_metric)

et cet exemple de jeu de données:

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

Je voudrais récupérer un tableau qui répertorie les mesures dans l'ordre (0,1,2,3 ..) avec le nombre total de fois où le décompte se produit. Donc, à partir de cet ensemble, vous vous retrouveriez avec:

0 3    
1 2    
2 2    
3 1

Je suis aux prises avec la syntaxe LINQ mais je suis coincé sur l'endroit où mettre un groupby et compter .... toute aide ??

POST Edit: Je n'ai jamais réussi à obtenir les réponses publiées car elles renvoyaient toujours un enregistrement avec le nombre de dénombrements différents. Cependant, j'ai pu assembler un exemple LINQ to SQL qui a fonctionné:

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

Ce résultat m'a donné un ensemble ordonné d'enregistrements avec des «métriques» et le nombre d'utilisateurs associés à chacun. Je suis clairement nouveau pour LINQ en général et à mon avis, cette approche semble très similaire à l'approche pure LINQ mais m'a donné une réponse différente.


Oui, mais l'explication de Jimmy m'a aidé davantage. Cependant, je n'ai jamais réussi à faire fonctionner son exemple, mais cela m'a conduit dans une nouvelle direction.
Gio

@Jimmy a utilisé la syntaxe fonctionnelle pour les expressions LINQ plutôt que la syntaxe de requête LINQ standard, et il a décidé d'afficher l'exécution immédiate de ces fonctions plutôt que le format d'exécution différée. Pour une nouvelle personne, ce serait déroutant. Je ne sais pas pourquoi il a fait ça.
Richard Robertson

Réponses:


395

Après avoir appelé GroupBy, vous obtenez une série de groupes IEnumerable<Grouping>, où chaque regroupement lui-même expose les éléments Keyutilisés pour créer le groupe et fait également partie IEnumerable<T>des éléments de votre ensemble de données d'origine. Il vous suffit d'appeler Count()ce groupement pour obtenir le sous-total.

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


C'était une réponse brillamment rapide, mais j'ai un petit problème avec la première ligne, en particulier "data.groupby (info => info.metric)"

Je suppose que vous avez déjà une liste / tableau de certains classqui ressemble à

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

Lorsque vous le faites data.GroupBy(x => x.metric), cela signifie "pour chaque élément xdans le IEnumerable défini par data, calculez-le .metric, puis regroupez tous les éléments avec la même métrique dans un Groupinget retournez un IEnumerablede tous les groupes résultants. Compte tenu de votre exemple d'ensemble de données 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

il en résulterait le résultat suivant après le 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]

C'était une réponse brillamment rapide mais j'ai un petit problème avec la première ligne, en particulier "data.groupby (info => info.metric)". De toute évidence, les «données» sont l'ensemble de données actuel, mais qu'est-ce que «info.metric» represet? la définition de classe?
Gio

"info.metric" serait la propriété / champ métrique de la classe UserInfo que vous avez mentionnée dans votre question.
lee-m

1
Merci d'avoir compris cela, mais en fait cela semble me donner une seule valeur - à savoir le nombre total de comptages métriques différents. Dans cet exemple, j'obtiens des "métriques 4" qui m'indiquent combien de comptes différents j'ai.
Gio

1
Sensationnel. Vous avez totalement expliqué le regroupement !! Cela valait à lui seul le poste .... je reçois toujours le résultat "metrics 4" mais merci!
Gio

4
Le début de cette réponse, "après avoir appelé GroupBy, vous obtenez une série de groupes IEnumerable <Grouping>, où chaque Grouping lui-même expose la clé utilisée pour créer le groupe et est également un IEnumerable <T> de tous les éléments qui se trouvent dans vos données d'origine set ", est l'explication la plus claire de LINQ GroupBy que j'ai encore lue, merci.
dumbledad

48

En supposant que userInfoListc'est List<UserInfo>:

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

La fonction lambda pour GroupBy(), n => n.metricsignifie qu'elle obtiendra le champ metricde chaque UserInfoobjet rencontré. Le type de ndépend du contexte, dans la première occurrence, il est de type UserInfo, car la liste contient des UserInfoobjets. Dans la deuxième occurrence nest de type Grouping, car maintenant c'est une liste d' Groupingobjets.

Groupings ont des méthodes d'extension comme .Count(), .Key()et à peu près tout ce que vous attendez. Tout comme vous vérifieriez .Lenghtun string, vous pouvez vérifier .Count()un groupe.


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

1
petite faute de frappe -> group.keydans la sélection (...) doit êtregroup.Key
Jan
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.