group-Klausel (C#-Referenz)group clause (C# Reference)

Die group-Klausel gibt eine Sequenz von IGrouping<TKey,TElement>-Objekten zurück, die null oder mehr Elemente enthalten, die mit dem Schlüsselwert für die Gruppe übereinstimmen.The group clause returns a sequence of IGrouping<TKey,TElement> objects that contain zero or more items that match the key value for the group. Sie können z.B. eine Sequenz von Zeichenfolgen entsprechend des ersten Buchstaben in jeder Zeichenfolge gruppieren.For example, you can group a sequence of strings according to the first letter in each string. In diesem Fall ist der erste Buchstabe der Schlüssel, verfügt über einen Typ char und wird in der Key-Eigenschaft jedes IGrouping<TKey,TElement>-Objekts gespeichert.In this case, the first letter is the key and has a type char, and is stored in the Key property of each IGrouping<TKey,TElement> object. Der Compiler leiten den Typ des Schlüssels her.The compiler infers the type of the key.

Sie können einen Abfrageausdruck mit einer group-Klausel beenden, so wie in folgendem Beispiel gezeigt:You can end a query expression with a group clause, as shown in the following example:

// Query variable is an IEnumerable<IGrouping<char, Student>>
var studentQuery1 =
    from student in students
    group student by student.Last[0];

Wenn Sie zusätzliche Abfragevorgänge für jede Gruppe ausführen möchten, können Sie einen temporären Bezeichner mithilfe des kontextuellen Schlüsselworts into angeben.If you want to perform additional query operations on each group, you can specify a temporary identifier by using the into contextual keyword. Wenn Sie into verwenden, müssen Sie mit der Abfrage fortfahren und sie entweder mit einer select-Anweisung oder einer anderen group-Klausel beenden, so wie im folgenden Auszug dargestellt:When you use into, you must continue with the query, and eventually end it with either a select statement or another group clause, as shown in the following excerpt:

// Group students by the first letter of their last name
// Query variable is an IEnumerable<IGrouping<char, Student>>
var studentQuery2 =
    from student in students
    group student by student.Last[0] into g
    orderby g.Key
    select g;

Weitere vollständige Beispiele des Gebrauchs von group mit und ohne into stehen im Abschnitt über Beispiele in diesem Thema bereit.More complete examples of the use of group with and without into are provided in the Example section of this topic.

Auflisten der Ergebnisse einer GruppenabfrageEnumerating the Results of a Group Query

Da die IGrouping<TKey,TElement>-Objekte, die von einer group-Abfrage erstellt wurden, praktisch eine Liste von Listen sind, müssen Sie eine geschachtelte foreach-Schleife verwenden, um auf die Elemente in jeder Gruppe zuzugreifen.Because the IGrouping<TKey,TElement> objects produced by a group query are essentially a list of lists, you must use a nested foreach loop to access the items in each group. Die äußere Schleife durchläuft die Gruppenschlüssel, und die innere Schleife durchläuft jedes Element in der Gruppe selbst.The outer loop iterates over the group keys, and the inner loop iterates over each item in the group itself. Eine Gruppe kann womöglich über einen Schlüssel verfügen, jedoch nicht über Elemente.A group may have a key but no elements. Nachstehend finden Sie die foreach-Schleife, die die Abfrage in den vorherigen Codebeispielen ausführen:The following is the foreach loop that executes the query in the previous code examples:

// Iterate group items with a nested foreach. This IGrouping encapsulates
// a sequence of Student objects, and a Key of type char.
// For convenience, var can also be used in the foreach statement.
foreach (IGrouping<char, Student> studentGroup in studentQuery2)
{
     Console.WriteLine(studentGroup.Key);
     // Explicit type for student could also be used here.
     foreach (var student in studentGroup)
     {
         Console.WriteLine("   {0}, {1}", student.Last, student.First);
     }
 }

SchlüsseltypenKey Types

Gruppenschlüssel können von jedem Typ sein, z.B. eine Zeichenfolge, ein integrierter numerischer Typ oder ein benutzerdefinierter benannter oder anonymer Typ.Group keys can be any type, such as a string, a built-in numeric type, or a user-defined named type or anonymous type.

Gruppieren nach ZeichenfolgeGrouping by string

Das vorherige Codebeispiel verwendete einen char.The previous code examples used a char. Es hätte stattdessen einfach ein Zeichenfolgenschlüssel angegeben werden können, z.B. der vollständige letzte Name.A string key could easily have been specified instead, for example the complete last name:

// Same as previous example except we use the entire last name as a key.
// Query variable is an IEnumerable<IGrouping<string, Student>>
 var studentQuery3 =
     from student in students
     group student by student.Last;

Gruppieren nach BoolGrouping by bool

Das folgende Beispiel zeigt die Verwendung eines booleschen Werts für einen Schlüssel, um die Ergebnisse in zwei Gruppen zu unterteilen.The following example shows the use of a bool value for a key to divide the results into two groups. Beachten Sie, dass der Wert durch einen Unterausdruck in der group-Klausel erstellt wird.Note that the value is produced by a sub-expression in the group clause.

class GroupSample1
{
    // The element type of the data source.
    public class Student
    {
        public string First { get; set; }
        public string Last { get; set; }
        public int ID { get; set; }
        public List<int> Scores;
    }

    public static List<Student> GetStudents()
    {
        // Use a collection initializer to create the data source. Note that each element
        //  in the list contains an inner sequence of scores.
        List<Student> students = new List<Student>
        {
           new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int> {97, 72, 81, 60}},
           new Student {First="Claire", Last="O'Donnell", ID=112, Scores= new List<int> {75, 84, 91, 39}},
           new Student {First="Sven", Last="Mortensen", ID=113, Scores= new List<int> {99, 89, 91, 95}},
           new Student {First="Cesar", Last="Garcia", ID=114, Scores= new List<int> {72, 81, 65, 84}},
           new Student {First="Debra", Last="Garcia", ID=115, Scores= new List<int> {97, 89, 85, 82}} 
        };

        return students;

    }

    static void Main()
    {
        // Obtain the data source.
        List<Student> students = GetStudents();

        // Group by true or false.
        // Query variable is an IEnumerable<IGrouping<bool, Student>>
        var booleanGroupQuery =
            from student in students
            group student by student.Scores.Average() >= 80; //pass or fail!

        // Execute the query and access items in each group
        foreach (var studentGroup in booleanGroupQuery)
        {
            Console.WriteLine(studentGroup.Key == true ? "High averages" : "Low averages");
            foreach (var student in studentGroup)
            {
                Console.WriteLine("   {0}, {1}:{2}", student.Last, student.First, student.Scores.Average());
            }
        }

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Output:
  Low averages
   Omelchenko, Svetlana:77.5
   O'Donnell, Claire:72.25
   Garcia, Cesar:75.5
  High averages
   Mortensen, Sven:93.5
   Garcia, Debra:88.25
*/

Gruppieren nach numerischen BereichGrouping by numeric range

Das nächste Beispiel verwendet einen Ausdruck, um einen nummerischen Gruppenschlüssel zu erstellen, der einen Prozentbereich darstellt.The next example uses an expression to create numeric group keys that represent a percentile range. Beachten Sie den Gebrauch von let an einer komfortablen Position zur Speicherung eines Ergebnisses eines Methodenaufrufs, damit Sie die Methode nicht zweimal in der group-Klausel aufrufen müssen.Note the use of let as a convenient location to store a method call result, so that you do not have to call the method two times in the group clause. Beachten Sie außerdem, dass in der group-Klausel eine Ausnahme durch Nulldivision vermieden wird, indem der Code überprüft, dass der Student keinen Durchschnitt von 0 hat.Note also in the group clause that to avoid a "divide by zero" exception the code checks to make sure that the student does not have an average of zero. Weitere Informationen zur sicheren Verwendung von Methoden in Abfrageausdrücken finden Sie unter Vorgehensweise: Behandeln von Ausnahmen in Abfrageausdrücken.For more information about how to safely use methods in query expressions, see How to: Handle Exceptions in Query Expressions.

class GroupSample2
{
    // The element type of the data source.
    public class Student
    {
        public string First { get; set; }
        public string Last { get; set; }
        public int ID { get; set; }
        public List<int> Scores;
    }

    public static List<Student> GetStudents()
    {
        // Use a collection initializer to create the data source. Note that each element
        //  in the list contains an inner sequence of scores.
        List<Student> students = new List<Student>
        {
           new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int> {97, 72, 81, 60}},
           new Student {First="Claire", Last="O'Donnell", ID=112, Scores= new List<int> {75, 84, 91, 39}},
           new Student {First="Sven", Last="Mortensen", ID=113, Scores= new List<int> {99, 89, 91, 95}},
           new Student {First="Cesar", Last="Garcia", ID=114, Scores= new List<int> {72, 81, 65, 84}},
           new Student {First="Debra", Last="Garcia", ID=115, Scores= new List<int> {97, 89, 85, 82}} 
        };

        return students;

    }

    // This method groups students into percentile ranges based on their
    // grade average. The Average method returns a double, so to produce a whole
    // number it is necessary to cast to int before dividing by 10. 
    static void Main()
    {
        // Obtain the data source.
        List<Student> students = GetStudents();

        // Write the query.
        var studentQuery =
            from student in students
            let avg = (int)student.Scores.Average()
            group student by (avg == 0 ? 0 : avg / 10) into g
            orderby g.Key
            select g;            

        // Execute the query.
        foreach (var studentGroup in studentQuery)
        {
            int temp = studentGroup.Key * 10;
            Console.WriteLine("Students with an average between {0} and {1}", temp, temp + 10);
            foreach (var student in studentGroup)
            {
                Console.WriteLine("   {0}, {1}:{2}", student.Last, student.First, student.Scores.Average());
            }
        }

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Output:
     Students with an average between 70 and 80
       Omelchenko, Svetlana:77.5
       O'Donnell, Claire:72.25
       Garcia, Cesar:75.5
     Students with an average between 80 and 90
       Garcia, Debra:88.25
     Students with an average between 90 and 100
       Mortensen, Sven:93.5
 */

Gruppieren nach zusammengesetzten SchlüsselnGrouping by Composite Keys

Verwenden Sie einen zusammengesetzten Schlüssel, wenn Sie Elemente gemäß mehrerer Schlüssel gruppieren möchten.Use a composite key when you want to group elements according to more than one key. Sie erstellen einen zusammengesetzten Schlüssel, indem Sie einen anonymen Typ oder einen benannten Typ verwenden, um das Schlüsselelement aufzunehmen.You create a composite key by using an anonymous type or a named type to hold the key element. Im folgenden Beispiel wird davon ausgegangen, dass eine Person-Klasse mit Elementen namens surname und city deklariert wurde.In the following example, assume that a class Person has been declared with members named surname and city. Die group-Klausel bewirkt, dass eine separate Gruppe für jede Gruppe von Personen mit dem gleichen Nachnamen und der gleichen Stadt erstellt wird.The group clause causes a separate group to be created for each set of persons with the same last name and the same city.

group person by new {name = person.surname, city = person.city};  

Verwenden Sie einen benannten Typ, wenn Sie die Abfragevariable an eine andere Methode übergeben müssen.Use a named type if you must pass the query variable to another method. Erstellen Sie eine spezielle Klasse mit automatisch implementierten Eigenschaften für die Schlüssel, und setzen Sie anschließend die Methoden Equals und GetHashCode außer Kraft.Create a special class using auto-implemented properties for the keys, and then override the Equals and GetHashCode methods. Sie können auch eine Struktur verwenden. In diesem Fall müssen Sie diese Methoden nicht unbedingt außer Kraft setzen.You can also use a struct, in which case you do not strictly have to override those methods. Weitere Informationen finden Sie unter Vorgehensweise: Implementieren einer einfachen Klasse mit automatisch implementierten Eigenschaften und Vorgehensweise: Abfragen von Dateiduplikaten in einer Verzeichnisstruktur (LINQ).For more information see How to: Implement a Lightweight Class with Auto-Implemented Properties and How to: Query for Duplicate Files in a Directory Tree. Das zweite Thema verfügt über ein Codebeispiel, das darstellt, wie ein zusammengesetzter Schlüssel mit benannten Typen verwendet wird.The latter topic has a code example that demonstrates how to use a composite key with a named type.

BeispielExample

Das folgende Beispiel zeigt das Standardmuster für das Sortieren von Quelldaten in Gruppen, wenn keine zusätzliche Abfragelogik auf die Gruppen angewendet wird.The following example shows the standard pattern for ordering source data into groups when no additional query logic is applied to the groups. Dies wird Gruppierung ohne Fortsetzung genannt.This is called a grouping without a continuation. Die Elemente in einem Zeichenfolgenarray werden gemäß des ersten Buchstabens gruppiert.The elements in an array of strings are grouped according to their first letter. Das Ergebnis der Abfrage ist ein IGrouping<TKey,TElement>-Typ, der eine öffentliche Key-Eigenschaft des Typs char und eine IEnumerable<T>-Sammlung enthält, die jedes Element in der Gruppierung enthält.The result of the query is an IGrouping<TKey,TElement> type that contains a public Key property of type char and an IEnumerable<T> collection that contains each item in the grouping.

Das Ergebnis einer group-Klausel ist eine Sequenz von Sequenzen.The result of a group clause is a sequence of sequences. Verwenden Sie deshalb eine geschachtelte foreach-Schleife innerhalb der Schleife, die die Gruppenschlüssel durchläuft – so wie in folgendem Beispiel gezeigt – um auf die einzelnen Elemente innerhalb jeder zurückgegebenen Gruppe zuzugreifen.Therefore, to access the individual elements within each returned group, use a nested foreach loop inside the loop that iterates the group keys, as shown in the following example.

class GroupExample1
{
    static void Main()
    {
        // Create a data source.
        string[] words = { "blueberry", "chimpanzee", "abacus", "banana", "apple", "cheese" };

        // Create the query.
        var wordGroups =
            from w in words
            group w by w[0];

        // Execute the query.
        foreach (var wordGroup in wordGroups)
        {
            Console.WriteLine("Words that start with the letter '{0}':", wordGroup.Key);
            foreach (var word in wordGroup)
            {
                Console.WriteLine(word);
            }
        }

        // Keep the console window open in debug mode
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }        
}
/* Output:
      Words that start with the letter 'b':
        blueberry
        banana
      Words that start with the letter 'c':
        chimpanzee
        cheese
      Words that start with the letter 'a':
        abacus
        apple
     */

BeispielExample

Dieses Beispiel zeigt, wie zusätzliche Logik auf die Gruppen ausgeführt wird, nachdem Sie diese erstellt haben, indem eine Fortsetzung mit into verwendet wird.This example shows how to perform additional logic on the groups after you have created them, by using a continuation with into. Weitere Informationen finden Sie unter into.For more information, see into. Das folgende Beispiel fragt jede Gruppe ab, wobei nur die Gruppe ausgewählt werden soll, dessen Schlüsselwert ein Vokal ist.The following example queries each group to select only those whose key value is a vowel.

class GroupClauseExample2
{
    static void Main()
    {
        // Create the data source.
        string[] words2 = { "blueberry", "chimpanzee", "abacus", "banana", "apple", "cheese", "elephant", "umbrella", "anteater" };

        // Create the query.
        var wordGroups2 =
            from w in words2
            group w by w[0] into grps
            where (grps.Key == 'a' || grps.Key == 'e' || grps.Key == 'i'
                   || grps.Key == 'o' || grps.Key == 'u')
            select grps;

        // Execute the query.
        foreach (var wordGroup in wordGroups2)
        {
            Console.WriteLine("Groups that start with a vowel: {0}", wordGroup.Key);
            foreach (var word in wordGroup)
            {
                Console.WriteLine("   {0}", word);
            }
        }

        // Keep the console window open in debug mode
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Output:
    Groups that start with a vowel: a
        abacus
        apple
        anteater
    Groups that start with a vowel: e
        elephant
    Groups that start with a vowel: u
        umbrella
*/    

HinweiseRemarks

group-Klauseln werden zur Kompilierzeit in Aufrufe der GroupBy-Methode übersetzt.At compile time, group clauses are translated into calls to the GroupBy method.

Siehe auchSee Also

IGrouping<TKey,TElement>
GroupBy
ThenBy
ThenByDescending
Abfrageschlüsselwörter (LINQ)Query Keywords (LINQ)
LINQ-AbfrageausdrückeLINQ Query Expressions
Gewusst wie: Erstellen einer geschachtelten GruppeHow to: Create a Nested Group
Gewusst wie: Gruppieren von AbfrageergebnissenHow to: Group Query Results
Gewusst wie: Ausführen einer Unterabfrage für eine GruppierungsoperationHow to: Perform a Subquery on a Grouping Operation