TOC

This article has been localized into German by the community.

LINQ:

Gruppieren von Daten: die GroupBy()-Methode

Bislang haben wir vor allem mit Datenlisten gearbeitet. Wir haben es sortiert, eingegrenzt und zu neuen Objekten geformt, aber es fehlt noch eine wichtige Operation: Gruppieren von Daten. Wenn du Daten gruppierst, nimmst du eine Liste von Dingen und teilst sie dann in mehrere Gruppen auf, basierend auf einer oder mehreren Eigenschaften. Stell dir einfach vor, wir hätten eine Datenquelle wie diese:

var users = new List<User>()
{
    new User { Name = "John Doe", Age = 42, HomeCountry = "USA" },
    new User { Name = "Jane Doe", Age = 38, HomeCountry = "USA" },
    new User { Name = "Joe Doe", Age = 19, HomeCountry = "Germany" },
    new User { Name = "Jenna Doe", Age = 19, HomeCountry = "Germany" },
    new User { Name = "James Doe", Age = 8, HomeCountry = "USA" },
};

Eine flache Liste von Benutzerobjekten, aber es könnte interessant sein, diese Benutzer nach z.B. ihrem Heimatland oder ihrem Alter zu gruppieren. Mit LINQ ist dies sehr einfach, auch wenn die Verwendung der GroupBy()-Methode am Anfang etwas verwirrend sein kann. Lassen Sie uns einen Blick darauf werfen, wie es funktioniert:

using System;    
using System.Collections.Generic;    
using System.Linq;    

namespace LinqGroup    
{    
    class Program    
    {    
static void Main(string[] args)    
{    
    var users = new List<User>()    
    {    
new User { Name = "John Doe", Age = 42, HomeCountry = "USA" },    
new User { Name = "Jane Doe", Age = 38, HomeCountry = "USA" },    
new User { Name = "Joe Doe", Age = 19, HomeCountry = "Germany" },    
new User { Name = "Jenna Doe", Age = 19, HomeCountry = "Germany" },    
new User { Name = "James Doe", Age = 8, HomeCountry = "USA" },    
    };    
    var usersGroupedByCountry = users.GroupBy(user => user.HomeCountry);    
    foreach(var group in usersGroupedByCountry)    
    {    
Console.WriteLine("Users from " + group.Key + ":");    
foreach(var user in group)    
Console.WriteLine("* " + user.Name);
    }    
}    

public class User    
{    
    public string Name { get; set; }    

    public int Age { get; set; }    

    public string HomeCountry { get; set; }    
}    
    }    
}

Die resultierende Ausgabe sieht in etwa so aus:

Users from USA:
* John Doe
* Jane Doe
* James Doe
Users from Germany:
* Joe Doe
* Jenna Doe

Das Beispiel mag etwas lang erscheinen, aber wie Sie bald feststellen werden, ist das meiste davon nur die Vorbereitung der Datenquelle. Denken Sie daran, dass alle Daten genauso gut aus einem XML-Dokument oder einer Datenbank stammen können - es ist lediglich einfacher, mit einer Objektdatenquelle zu demonstrieren, dass Sie sie so verwenden können, wie sie ist.

Der interessante Teil ist, wenn wir die Variable usersGroupedByCountry erstellen. Wir machen es, indem wir die GroupBy()-Methode auf unserer Datenquelle anwenden und den Parameter angeben, nach dem wir die Daten gruppieren möchten. In diesem Fall möchte ich, dass die Benutzer nach ihrem Heimatland gruppiert werden, also ist das die Eigenschaft, die ich der GroupBy()-Methode bereitstelle. Das Ergebnis ist ein Objekt mit einer Key-Eigenschaft, die den Wert der von uns gruppierten Eigenschaft (in diesem Fall HomeCountry) sowie alle zur Gruppe gehörenden Objekte enthält. Wir verwenden das in den nächsten Zeilen, um über die Gruppen zu iterieren, die wir gerade erstellt haben, und für jede Gruppe drucken wir den Schlüssel (HomeCountry) und dann iterieren und drucken wir alle Benutzerobjekte aus der Gruppe.

Benutzerdefinierte Gruppenschlüssel

Wie du sehen kannst, ist die Gruppierung nach einer bestehenden Eigenschaft kinderleicht, aber wie du vielleicht schon erfahren hast, sind die LINQ-Methoden sehr flexibel. Es ist genauso einfach, deine eigenen, benutzerdefinierten Gruppen zu erstellen, basierend auf was auch immer du willst - ein Beispiel dafür könnte das folgende sein, wo wir Gruppen basierend auf den ersten beiden Buchstaben des Benutzernamens erstellen:

using System;
using System.Collections.Generic;
using System.Linq;

namespace LinqGroup
{
    class Program
    {
static void Main(string[] args)
{
    var users = new List<User>()
    {
new User { Name = "John Doe", Age = 42, HomeCountry = "USA" },
new User { Name = "Jane Doe", Age = 38, HomeCountry = "USA" },
new User { Name = "Joe Doe", Age = 19, HomeCountry = "Germany" },
new User { Name = "Jenna Doe", Age = 19, HomeCountry = "Germany" },
new User { Name = "James Doe", Age = 8, HomeCountry = "USA" },
    };
    var usersGroupedByFirstLetters = users.GroupBy(user => user.Name.Substring(0, 2));
    foreach(var group in usersGroupedByFirstLetters)
    {
Console.WriteLine("Users starting with " + group.Key + ":");
foreach(var user in group)
    Console.WriteLine("* " + user.Name);
    }
}

public class User
{
    public string Name { get; set; }

    public int Age { get; set; }

    public string HomeCountry { get; set; }
}
    }
}

Wir rufen einfach die Substring()-Methode auf, um die beiden ersten Buchstaben zu erhalten, und dann erstellt LINQ die darauf basierenden Benutzergruppen. Das Ergebnis wird in etwa so aussehen:

Users starting with Jo:
* John Doe
* Joe Doe
Users starting with Ja:
* Jane Doe
* James Doe
Users starting with Je:
* Jenna Doe

Wie du sehen kannst, steht es uns frei, eine Methode innerhalb der GroupBy()-Methode aufzurufen - tatsächlich können wir dort so ziemlich alles tun, was wir wollen, solange wir etwas zurückgeben, das LINQ zur Gruppierung der Elemente verwenden kann. Wir können sogar eine Methode erstellen, die eine neue Information über das Element zurückgibt und sie dann zum Erstellen einer Gruppe verwendet, wie wir es im nächsten Beispiel tun:

using System;
using System.Collections.Generic;
using System.Linq;

namespace LinqGroup
{
    class Program
    {
static void Main(string[] args)
{
    var users = new List<User>()
    {
new User { Name = "John Doe", Age = 42, HomeCountry = "USA" },
new User { Name = "Jane Doe", Age = 38, HomeCountry = "USA" },
new User { Name = "Joe Doe", Age = 19, HomeCountry = "Germany" },
new User { Name = "Jenna Doe", Age = 19, HomeCountry = "Germany" },
new User { Name = "James Doe", Age = 8, HomeCountry = "USA" },
    };
    var usersGroupedByAgeGroup = users.GroupBy(user => user.GetAgeGroup());
    foreach(var group in usersGroupedByAgeGroup)
    {
Console.WriteLine(group.Key + ":");
foreach(var user in group)
    Console.WriteLine("* " + user.Name + " [" + user.Age + " years]");
    }
}

public class User
{
    public string Name { get; set; }

    public int Age { get; set; }

    public string HomeCountry { get; set; }

    public string GetAgeGroup()
    {
if (this.Age < 13)
    return "Children";
if (this.Age < 20)
    return "Teenagers";
return "Adults";
    }
}
    }
}

Beachten Sie, wie ich eine Methode GetAgeGroup() für die Benutzerklasse implementiert habe. Es gibt eine Zeichenfolge zurück, die die Altersgruppe des Benutzers definiert, und wir rufen sie einfach in der GroupBy() -Methode auf, um sie als Gruppenschlüssel zu verwenden. Das Ergebnis sieht folgendermaßen aus:

Adults:
* John Doe [42 years]
* Jane Doe [38 years]
Teenagers:
* Joe Doe [19 years]
* Jenna Doe [19 years]
Children:
* James Doe [8 years]

Ich wähle die Methode GetAgeGroup() für die User-Klasse zu implementieren, da sie an anderen Stellen nützlich sein kann, aber manchmal braucht man nur eine kurze Logik, um die Gruppen zu erstellen und nicht woanders wiederzuverwenden. In diesen Situationen können Sie die Logik direkt der GroupBy() - Methode als Lambda-Ausdruck wie folgt zur Verfügung stellen:

var usersGroupedByAgeGroup = users.GroupBy(user =>
    {
if (user.Age < 13)
    return "Children";
if (user.Age < 20)
    return "Teenagers";
return "Adults";
    });

Das Ergebnis ist natürlich das selbe!

Gruppierung nach einem zusammengesetzten Schlüssel

Bisher waren die Schlüssel unserer Gruppen nur ein einziger Wert, z.B.: eine Eigenschaft oder das Ergebnis eines Methodenaufrufs Es steht Ihnen jedoch frei, eigene Schlüssel zu erstellen, die mehrere Werte enthalten - diese werden zusammengesetzte Schlüssel genannt. Ein Anwendungsbeispiel könnte sein, wenn wir unsere Nutzer sowohl nach ihrem Heimatland als auch nach ihrem Alter gruppieren möchten:

using System;
using System.Collections.Generic;
using System.Linq;

namespace LinqGroup2
{
    class Program
    {
static void Main(string[] args)
{
    var users = new List<User>()
    {
new User { Name = "John Doe", Age = 42, HomeCountry = "USA" },
new User { Name = "Jane Doe", Age = 38, HomeCountry = "USA" },
new User { Name = "Joe Doe", Age = 19, HomeCountry = "Germany" },
new User { Name = "Jenna Doe", Age = 19, HomeCountry = "Germany" },
new User { Name = "James Doe", Age = 8, HomeCountry = "USA" },
    };

    var usersGroupedByCountryAndAge = users.GroupBy(user => new { user.HomeCountry, user.Age });
    foreach(var group in usersGroupedByCountryAndAge)
    {
Console.WriteLine("Users from " + group.Key.HomeCountry + " at the age of " + group.Key.Age + ":");
foreach (var user in group)
    Console.WriteLine("* " + user.Name + " [" + user.Age + " years]");
    }
}

public class User
{
    public string Name { get; set; }

    public int Age { get; set; }

    public string HomeCountry { get; set; }

}
    }
}

Beachten Sie die Syntax, die wir in der GroupBy() -Methode verwenden. Anstatt eine einzelne Eigenschaft anzugeben, erstellen wir ein neues anonymes Objekt, das die Eigenschaften HomeCountry und Age enthält. LINQ erstellt jetzt basierend auf diesen beiden Eigenschaften Gruppen und hängt das anonyme Objekt an die Key-Eigenschaft der Gruppe an. Wir können beide Eigenschaften verwenden, wenn wir über die Gruppen iterieren, wie Sie sehen können. Das Ergebnis sieht ungefähr so aus:

Users from USA at the age of 42:
* John Doe [42 years]
Users from USA at the age of 38:
* Jane Doe [38 years]
Users from Germany at the age of 19:
* Joe Doe [19 years]
* Jenna Doe [19 years]
Users from USA at the age of 8:
* James Doe [8 years]

Wie immer haben wir in diesem Artikel die LINQ-Methodensyntax verwendet. Erlauben Sie mir jedoch, Ihnen ein vergleichendes Beispiel zu geben, wie es mit der LINQ-Abfragesyntax gemacht werden könnte:

// Method syntax
var usersGroupedByCountryAndAge = users.GroupBy(user => new { user.HomeCountry, user.Age });
// Query syntax
var usersGroupedByCountryAndAgeQ = from user in users group user by new { user.HomeCountry, user.Age } into userGroup select userGroup;

Zusammenfassung

Wie Sie anhand der Beispiele in diesem Artikel sehen können, ist die GroupBy() -Methode von LINQ extrem leistungsfähig. Sie ermöglicht Ihnen Ihre Daten auf neue Art und Weise mit sehr wenig Code zu verwenden. Früher war dies entweder sehr mühsam oder erforderte eine relationale Datenbank. Mit LINQ können Sie jedoch die Datenquelle verwenden, die Sie möchten, und trotzdem die gleiche, einfach zu verwendende Funktionalität erhalten.


This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!