LINQ mit groupby und count


221

Das ist ziemlich einfach, aber ich bin ratlos: Angesichts dieser Art von Datensatz:

UserInfo(name, metric, day, other_metric)

und dieser Beispieldatensatz:

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

Ich möchte eine Tabelle abrufen, in der die Metriken in der Reihenfolge (0,1,2,3 ..) mit der Gesamtanzahl der Zählungen aufgelistet sind. Aus diesem Set würden Sie also Folgendes erhalten:

0 3    
1 2    
2 2    
3 1

Ich beschäftige mich mit der LINQ-Syntax, bin aber nicht sicher, wo ich ein Groupby platzieren und zählen soll ... jede Hilfe?

POST-Bearbeitung: Ich konnte die veröffentlichten Antworten nie zum Laufen bringen, da sie immer einen Datensatz mit der Anzahl der verschiedenen Zählungen zurückgaben. Ich konnte jedoch ein LINQ to SQL-Beispiel zusammenstellen, das funktionierte:

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

Dieses Ergebnis gab mir einen geordneten Satz von Datensätzen mit 'Metriken' und der Anzahl der Benutzer, die jedem zugeordnet sind. Ich bin eindeutig neu in LINQ im Allgemeinen und für mein ungeübtes Auge scheint dieser Ansatz dem reinen LINQ-Ansatz sehr ähnlich zu sein, gab mir jedoch eine andere Antwort.


Ja, aber Jimmy's Erklärung hat mir mehr geholfen. Ich konnte sein Beispiel jedoch nie zum Laufen bringen, aber es führte mich in eine neue Richtung.
Gio

@Jimmy verwendete die funktionale Syntax für LINQ-Ausdrücke anstelle der Standard-LINQ-Abfragesyntax. Außerdem entschied er sich, die sofortige Ausführung dieser Funktionen anstelle des Formats für die verzögerte Ausführung anzuzeigen. Für eine neue Person wäre das verwirrend. Ich weiß nicht, warum er das getan hat.
Richard Robertson

Antworten:


394

Nach dem Aufruf erhalten GroupBySie eine Reihe von Gruppen IEnumerable<Grouping>, in denen jede Gruppierung selbst die Keyzum Erstellen der Gruppe verwendeten IEnumerable<T>Elemente verfügbar macht und auch zu den Elementen in Ihrem Originaldatensatz gehört. Sie müssen nur Count()diese Gruppierung aufrufen , um die Zwischensumme zu erhalten.

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


Dies war eine brillant schnelle Antwort, aber ich habe ein kleines Problem mit der ersten Zeile, insbesondere "data.groupby (info => info.metric)".

Ich gehe davon aus, dass Sie bereits eine Liste / ein Array von einigen haben class, die so aussehen

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

Wenn Sie dies tun data.GroupBy(x => x.metric), bedeutet dies "für jedes Element xin der IEnumerable, definiert durch data, berechnen Sie es .metric, gruppieren Sie dann alle Elemente mit derselben Metrik in a Groupingund geben Sie eine IEnumerablealler resultierenden Gruppen zurück. Geben Sie Ihren Beispieldatensatz an

    <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

es würde nach dem groupby zu folgendem Ergebnis führen:

(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]

Dies war eine brillant schnelle Antwort, aber ich habe ein kleines Problem mit der ersten Zeile, insbesondere "data.groupby (info => info.metric)". Einfach "Daten" ist der aktuelle Datensatz, aber was gibt "info.metric" wieder? die Klassendefinition?
Gio

"info.metric" ist die metrische Eigenschaft / das metrische Feld in der UserInfo-Klasse, die Sie in Ihrer Frage erwähnt haben.
Lee-m

1
Danke, habe das herausgefunden, aber tatsächlich scheint mir dies einen einzigen Wert zu geben - nämlich die Gesamtzahl der verschiedenen Metriken. In diesem Beispiel erhalte ich "Metriken 4", die mir anzeigen, wie viele verschiedene Zählungen ich habe.
Gio

1
Beeindruckend. Du hast die Gruppierung total erklärt !! Das allein war den Beitrag wert ... ich bekomme immer noch das "Metrics 4" -Ergebnis, aber danke!
Gio

4
Der Anfang dieser Antwort: "Nach dem Aufruf von GroupBy erhalten Sie eine Reihe von Gruppen IEnumerable <Grouping>, wobei jede Gruppierung selbst den zum Erstellen der Gruppe verwendeten Schlüssel verfügbar macht und auch eine IEnumerable <T> aller Elemente in Ihren Originaldaten ist set ", ist die klarste Erklärung für LINQ GroupBy, die ich bisher gelesen habe, danke.
Dumbledad

48

Angenommen, userInfoListist ein List<UserInfo>:

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

Die Lambda - Funktion für GroupBy(), n => n.metricbedeutet , dass es Feld bekommt metricvon jedem UserInfobegegnet Objekt. Der Typ nist abhängig vom Kontext, beim ersten Auftreten ist er vom Typ UserInfo, da die Liste UserInfoObjekte enthält . Im zweiten Fall nhandelt es sich um einen Typ Grouping, da es sich nun um eine Liste von GroupingObjekten handelt.

Groupings haben Erweiterungsmethoden wie .Count(), .Key()und so ziemlich alles andere, die Sie erwarten. So wie Sie überprüfen würde .Lenghtauf ein string, können Sie überprüfen , .Count()auf eine Gruppe.


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

1
kleiner Tippfehler -> group.keyin der Auswahl (...) muss seingroup.Key
Januar
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.