Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
De group component retourneert een reeks IGrouping<TKey,TElement> objecten. De reeks bevat nul of meer items die overeenkomen met de sleutelwaarde voor de groep. U kunt bijvoorbeeld een reeks tekenreeksen groeperen op basis van de eerste letter in elke tekenreeks. In dit geval is de eerste letter de sleutel en heeft een typeteken. Elk IGrouping<TKey,TElement> object slaat deze sleutel op in Key de eigenschap. De compiler bepaalt het type sleutel.
De C#-taalreferentiedocumenten beschrijven de meest recent uitgebrachte versie van de C#-taal. Het bevat ook de eerste documentatie voor functies in openbare previews voor de aanstaande taalrelease.
De documentatie identificeert alle functies die voor het eerst zijn geïntroduceerd in de laatste drie versies van de taal of in de huidige openbare previews.
Aanbeveling
Raadpleeg het artikel over de versiegeschiedenis van de C#-taal om te achterhalen wanneer een functie voor het eerst is geïntroduceerd in C#.
U kunt een query-expressie beëindigen met een group component, zoals wordt weergegeven in het volgende voorbeeld:
// Query variable is an IEnumerable<IGrouping<char, Student>>
var studentQuery1 =
from student in students
group student by student.Last[0];
Als u extra querybewerkingen voor elke groep wilt uitvoeren, geeft u een tijdelijke id op met behulp van het in contextuele trefwoord. Wanneer u into gebruikt, moet u doorgaan met de query en deze uiteindelijk beëindigen met een select instructie of een andere group clausule, zoals wordt weergegeven in het volgende fragment:
// 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;
In de sectie Voorbeeld van dit artikel vindt u meer volledige voorbeelden van het gebruik van group met en zonder into .
De resultaten van een groepsquery opsommen
Omdat de IGrouping<TKey,TElement> objecten die een group query produceert in feite een lijst met lijsten zijn, moet u een geneste foreach-lus gebruiken om toegang te krijgen tot de items in elke groep. De buitenste lus doorloopt de groepssleutels en de binnenste lus doorloopt elk item in de groep zelf. Een groep kan een sleutel hebben, maar geen elementen. Met de volgende foreach lus wordt de query uitgevoerd in de vorige codevoorbeelden:
// 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);
}
}
Sleuteltypen
Groepssleutels kunnen elk type zijn, zoals een tekenreeks, een ingebouwd numeriek type, of een door de gebruiker gedefinieerd benoemd type of een anoniem type.
Groeperen op tekenreeks
De vorige codevoorbeelden gebruikten een char. U kunt ook een tekenreekssleutel opgeven, zoals de volledige achternaam:
// 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;
Groeperen op bool
In het volgende voorbeeld wordt een boolwaarde voor een sleutel gebruikt om de resultaten in twee groepen te verdelen. De waarde is afkomstig van een subexpressie in de group component.
class GroupSample1
{
// The element type of the data source.
public class Student
{
public required string First { get; init; }
public required string Last { get; init; }
public required int ID { get; init; }
public required 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 Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= [97, 72, 81, 60]},
new Student {First="Claire", Last="O'Donnell", ID=112, Scores= [75, 84, 91, 39]},
new Student {First="Sven", Last="Mortensen", ID=113, Scores= [99, 89, 91, 95]},
new Student {First="Cesar", Last="Garcia", ID=114, Scores= [72, 81, 65, 84]},
new Student {First="Debra", Last="Garcia", ID=115, Scores= [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());
}
}
}
}
/* 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
*/
Groeperen op numeriek bereik
In het volgende voorbeeld wordt een expressie gebruikt om numerieke groepssleutels te maken die een percentielbereik vertegenwoordigen. Het gebruikt let om een resultaat van een methode-aanroep op te slaan, dus u hoeft de methode niet tweemaal aan te roepen in de group component. Zie Uitzonderingen in query-expressies afhandelen voor meer informatie over het veilig gebruiken van methoden in query-expressies.
class GroupSample2
{
// The element type of the data source.
public class Student
{
public required string First { get; init; }
public required string Last { get; init; }
public required int ID { get; init; }
public required 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 Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= [97, 72, 81, 60]},
new Student {First="Claire", Last="O'Donnell", ID=112, Scores= [75, 84, 91, 39]},
new Student {First="Sven", Last="Mortensen", ID=113, Scores= [99, 89, 91, 95]},
new Student {First="Cesar", Last="Garcia", ID=114, Scores= [72, 81, 65, 84]},
new Student {First="Debra", Last="Garcia", ID=115, Scores= [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 / 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 {temp} and {temp + 10}");
foreach (var student in studentGroup)
{
Console.WriteLine(" {0}, {1}:{2}", student.Last, student.First, student.Scores.Average());
}
}
}
}
/* 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
*/
Groeperen op samengestelde sleutels
Gebruik een samengestelde sleutel als u elementen wilt groeperen op meer dan één sleutel. Maak een samengestelde sleutel met behulp van een anoniem type of een benoemd type voor het opslaan van het sleutelelement. In het volgende voorbeeld wordt ervan uitgegaan dat een klasse Person leden heeft met de naam surname en city. De group component maakt een afzonderlijke groep voor elke groep personen met dezelfde achternaam en dezelfde plaats.
group person by new {name = person.surname, city = person.city};
Gebruik een benoemd type als u de queryvariabele moet doorgeven aan een andere methode. Maak een speciale klasse met automatisch geïmplementeerde eigenschappen voor de sleutels en overschrijf vervolgens de Equals en GetHashCode methoden. U kunt ook een struct gebruiken, waarvoor deze methode-onderdrukkingen niet strikt vereist zijn. Zie Een lichtgewicht klasse implementeren met automatisch geïmplementeerde eigenschappen en query's uitvoeren op dubbele bestanden in een mapstructuur voor meer informatie. Het laatste artikel bevat een codevoorbeeld dat laat zien hoe u een samengestelde sleutel gebruikt met een benoemd type.
Voorbeelden
In het volgende voorbeeld ziet u het standaardpatroon voor het ordenen van brongegevens in groepen wanneer u geen extra querylogica toepast op de groepen. Dit patroon wordt groepering genoemd zonder vervolg. Het voorbeeld groepeert de elementen in een matrix met tekenreeksen op basis van de eerste letter. Het resultaat van de query is een IGrouping<TKey,TElement> type dat een openbare Key eigenschap van het type char bevat en een IEnumerable<T> verzameling die elk item in de groepering bevat.
Het resultaat van een group component is een reeks reeksen. Als u toegang wilt krijgen tot de afzonderlijke elementen binnen elke geretourneerde groep, gebruikt u een geneste foreach lus binnen de lus die de groepssleutels doorloopt, zoals wordt weergegeven in het volgende voorbeeld.
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 '{wordGroup.Key}':");
foreach (var word in wordGroup)
{
Console.WriteLine(word);
}
}
}
}
/* 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
*/
In het volgende voorbeeld ziet u hoe u extra logica uitvoert voor de groepen nadat u ze hebt gemaakt, met behulp van een vervolg met into. Zie into voor meer informatie. In het volgende voorbeeld wordt elke groep bevraagd om alleen die groepen te selecteren waarvan de sleutelwaarde een klinker is.
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: {wordGroup.Key}");
foreach (var word in wordGroup)
{
Console.WriteLine($" {word}");
}
}
}
}
/* 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
*/
Tijdens het compileren vertaalt group de compiler componenten in aanroepen naar de GroupBy methode.
De syntaxis van group de componentquery biedt geen ondersteuning voor aangepaste gelijkheidsgelijker. Als u in uw query wilt gebruiken IEqualityComparer , gebruikt GroupBy u de methode expliciet.