group – klauzule (Referenční dokumentace jazyka C#)
groupKlauzule vrací sekvenci IGrouping<TKey,TElement> objektů, které obsahují nula nebo více položek, které odpovídají hodnotě klíče pro skupinu. Například můžete seskupit sekvenci řetězců podle prvního písmene v každém řetězci. V tomto případě je prvním písmenem klíč a má typ chara je uložen ve Key vlastnosti každého IGrouping<TKey,TElement> objektu. Kompilátor odvodí typ klíče.
Můžete ukončit výraz dotazu s group klauzulí, jak je znázorněno v následujícím příkladu:
// Query variable is an IEnumerable<IGrouping<char, Student>>
var studentQuery1 =
from student in students
group student by student.Last[0];
Pokud chcete pro každou skupinu provést další operace dotazování, můžete zadat dočasný identifikátor pomocí klíčového slova into . Když použijete into , musíte pokračovat v dotazu a nakonec ho ukončit buď pomocí select příkazu, nebo jiné group klauzule, jak je znázorněno v následujícím výňatku:
// 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;
group into V příkladu v tomto článku jsou uvedeny úplnější příklady použití příkazů with a bez nich.
Vyčíslení výsledků dotazu skupiny
Vzhledem k tomu IGrouping<TKey,TElement> , že objekty vytvořené group dotazem jsou v podstatě seznam seznamů, je nutné použít vnořenou smyčku foreach pro přístup k položkám v každé skupině. Vnější smyčka projde klíče skupiny a vnitřní smyčka projde každou položku v samotné skupině. Skupina může mít klíč, ale neobsahuje žádné prvky. Následuje foreach smyčka, která spouští dotaz v předchozích příkladech kódu:
// 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);
}
}
Typy klíčů
Klíče skupiny mohou být libovolného typu, jako je například řetězec, vestavěný číselný typ nebo uživatelsky definovaný pojmenovaný typ nebo anonymní typ.
Seskupení podle řetězce
Předchozí příklady kódu používaly char . Místo toho je možné zadat klíč řetězce, například poslední příjmení:
// 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;
Seskupení podle bool
Následující příklad ukazuje použití bool hodnoty pro klíč k rozdělení výsledků do dvou skupin. Všimněte si, že hodnota je vytvořena dílčím výrazem v group klauzuli.
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
*/
Seskupení podle číselného rozsahu
Následující příklad používá výraz pro vytvoření číselné skupiny klíčů, které reprezentují rozsah percentilu. Všimněte si použití let jako vhodného umístění pro uložení výsledku volání metody, takže nemusíte volat metodu dvakrát v group klauzuli. Další informace o bezpečném použití metod ve výrazech dotazů naleznete v tématu zpracování výjimek ve výrazech dotazů.
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 / 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
*/
Seskupení podle složených klíčů
Pokud chcete seskupit prvky podle více než jednoho klíče, použijte složený klíč. Složený klíč vytvoříte pomocí anonymního typu nebo pojmenovaného typu pro uložení klíčového elementu. V následujícím příkladu Předpokládejme, že třída Person byla deklarována s členy s názvem surname a city . groupKlauzule způsobí vytvoření samostatné skupiny pro každou sadu osob se stejným názvem a stejným městem.
group person by new {name = person.surname, city = person.city};
Pojmenovaný typ použijte v případě, že je nutné předat proměnnou dotazu jiné metodě. Vytvořte speciální třídu pomocí automaticky implementovaných vlastností klíčů a potom přepište Equals GetHashCode metody a. Můžete také použít strukturu. v takovém případě není nutné tyto metody přepsat bezpodmínečně. Další informace najdete v tématu implementace odlehčené třídy s automaticky implementovanými vlastnostmi a Postup dotazování na duplicitní soubory v adresářovém stromu. Druhý článek obsahuje příklad kódu, který ukazuje, jak použít složený klíč s pojmenovaným typem.
Příklad 1
Následující příklad ukazuje standardní vzor pro řazení zdrojových dat do skupin, pokud se pro skupiny nepoužívá žádná další logika dotazu. Označuje se jako seskupení bez pokračování. Prvky v poli řetězců jsou seskupeny podle jejich prvního písmene. Výsledek dotazu je IGrouping<TKey,TElement> typ, který obsahuje veřejnou Key vlastnost typu char a IEnumerable<T> kolekci, která obsahuje každou položku v seskupení.
Výsledkem group klauzule je sekvence sekvencí. Proto pro přístup k jednotlivým prvkům v rámci jednotlivých vrácených skupin použijte vnořenou foreach smyčku uvnitř smyčky, která provede iteraci klíčů skupiny, jak je znázorněno v následujícím příkladu.
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
*/
Příklad 2
Tento příklad ukazuje, jak provést další logiku pro skupiny po jejich vytvoření pomocí pokračování s into . Další informace najdete v tématu. Následující příklad dotazuje každou skupinu na výběr pouze těch, jejichž klíčová hodnota je samohláska.
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
*/
Poznámky
V době kompilace group jsou klauzule přeloženy do volání GroupBy metody.