cláusula Group (referência de C#)
O group cláusula retorna uma seqüência de IGrouping<TKey, TElement> objetos que contêm zero ou mais itens que coincidem com o valor da chave para o grupo.Por exemplo, você pode agrupar uma seqüência de cadeias de caracteres de acordo com a primeira letra de cada seqüência de caracteres.Nesse caso, a primeira letra é a chave e tem um tipo de chare é armazenado na Key propriedade de cada IGrouping<TKey, TElement> objeto.O compilador infere o tipo da chave.
Você pode finalizar uma expressão de consulta com um group cláusula, conforme mostrado no exemplo a seguir:
// Query variable is an IEnumerable<IGrouping<char, Student>>
var studentQuery1 =
from student in students
group student by student.Last[0];
Se você quiser executar operações de consulta adicionais em cada grupo, você pode especificar um identificador temporário usando o em palavra-chave contextual.Quando você usa into, você deve continuar com a consulta e eventualmente encerrá-lo com um um select instrução ou outro group cláusula, conforme mostrado no trecho a seguir:
// 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;
Mais completas de exemplos do uso de group com e sem into são fornecidos na seção exemplo deste tópico.
Enumerando os resultados de uma consulta de grupo
Porque o IGrouping<TKey, TElement> objetos produzidos por um group consulta são essencialmente uma lista de listas, você deve usar um aninhadas foreach loop para acessar os itens em cada grupo.O loop externo itere sobre as chaves de grupo e o loop interno é iterado em cada item do grupo propriamente dito.Um grupo pode ter uma chave, mas nenhum elemento.A seguir está o foreach loop que executa a consulta nos exemplos de código anterior:
// 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);
}
}
Tipos de chaves
Chaves de grupo podem ser qualquer tipo, como uma seqüência de caracteres, um tipo numérico interno ou definido um usuário chamado tipo ou tipo anônimo.
Agrupando por string
Os exemplos de código anterior usados um char.Uma string key poderia facilmente foram especificada em vez disso, por exemplo, o sobrenome completo:
// 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;
Agrupando por bool
O exemplo a seguir mostra o uso de um valor booleano para uma chave dividir os resultados em dois grupos.Observe que o valor produzido por uma subexpressão na group cláusula.
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
*/
Agrupando por intervalo numérico
O próximo exemplo utiliza uma expressão para criar chaves de grupo numérico que representam uma faixa percentil.Observe o uso de permitem que como um local conveniente para armazenar um método de chamada como resultado, para que você não precisará chamar o método duas vezes na group cláusula.Observe também na group cláusula que para evitar uma exceção de "divisão por zero", o código verifica para certificar-se de que o aluno não possui uma média de zero.Para obter mais informações sobre como usar com segurança os métodos em expressões de consulta, consulte Como: tratar exceções em expressões de consulta (guia de programação do C#).
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
*/
Agrupando pelas chaves compostas
Quando você deseja agrupar elementos de acordo com a mais de uma chave, use uma chave composta.Você pode criar uma chave composta por meio de um tipo anônimo ou um tipo nomeado para conter um elemento-chave.O exemplo a seguir, suponha que uma classe Person ter sido declarado com membros chamados surname e city.O group cláusula faz com que um grupo separado seja criado para cada conjunto de pessoas com o mesmo sobrenome e da mesma cidade.
group person by new {name = person.surname, city = person.city};
Se você deve passar a variável de consulta para outro método, use um tipo nomeado.Crie uma classe especial usando propriedades de auto-implementado para as chaves e, em seguida, substituir o Equals e GetHashCode métodos.Você também pode usar uma struct, caso em que você não estritamente precisará substituir esses métodos.Para obter mais informações, consulte Como: implementar uma classe simplificada com propriedades de Auto-implementado (guia de programação do C#) e Como: consulta por arquivos duplicados em uma árvore de diretório (LINQ).O último tópico tem um exemplo de código que demonstra como usar uma chave composta com um tipo nomeado.
Exemplo
O exemplo a seguir mostra o padrão para ordenação de dados de origem em grupos quando nenhuma lógica de consulta adicional é aplicada aos grupos.Isso é chamado um agrupamento sem uma continuação.Os elementos em uma matriz de seqüências de caracteres são agrupados de acordo com sua primeira letra.O resultado da consulta é um IGrouping<TKey, TElement> tipo que contém um relatório público Key propriedade do tipo char e um IEnumerable<T> coleção que contém a cada item no agrupamento.
O resultado de uma group cláusula é uma seqüência de seqüências.Portanto, para acessar os elementos individuais dentro de cada grupo retornado, use um aninhadas foreach loop dentro do loop que itera as chaves de grupo, conforme mostrado no exemplo a seguir.
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
*/
Este exemplo mostra como executar lógica adicional nos grupos, após você ter criado-los, usando um continuação com into.Para obter mais informações, consulte em (C# referência).O exemplo a seguir consulta cada grupo para selecionar somente aqueles cujo valor da chave é uma vogal.
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
*/
Comentários
Em tempo de compilação, group cláusulas são traduzidas em chamadas para o GroupBy método.
Consulte também
Tarefas
Como: criar um grupo aninhado (guia de programação do C#)
Como: resultados de consulta de grupo (guia de programação do C#)
Como: executar uma subconsulta em uma operação de agrupamento (guia de programação do C#)
Referência
Conceitos
Expressões de consulta do LINQ (guia de programação do C#)