5. Projecting Grouped Elements into a New Type
The general group by
function when using query expression syntax returns the same element
type as the source collection elements. If you would
like the grouped elements to be in a different form, you must use the
extension method syntax and specify your own “element selector”
expression. The element selector expression takes an instance of the
original element and returns a new type based on the supplied
expression.
Listing 7 demonstrates how to group Contact records by state and return a group of strings rather than a group of Contact instances for each element (Contact
is the original element type). In this case, a string is returned by
concatenating the contact’s first and last name. The Console output
result is shown in Output 4.
Listing 7. Group elements can be projected to any type. This sample projects
group elements as a string type, rather than the default Contact instance—see Output 4
IList<Contact> contacts = Contact.SampleData();
var q = contacts.GroupBy( c => c.State, c => c.FirstName + " " + c.LastName);
foreach (var group in q) { Console.WriteLine("State: {0}", group.Key); foreach (string name in group) Console.WriteLine(" {0}", name); }
|
Output 4.
State: CA Barney Gottshall Mandy Gottshall Anthony Gauwain Jeffery Deane State: WA Bernadette Gottshall Armando Valdes Stewart Kagel Chance Lard State: AK Adam Gauwain Chris Gauwain State: FL Collin Zeeman State: TX Blaine Reifsteck Mack Kamph State: OR Ariel Hazelgrove
|
To demonstrate a slightly more complicated example, Listing 8
demonstrates projecting each group element into an anonymous type. This
example also shows how to use the Null-Coalescing Operator to handle
missing data in either the grouping predicate or the element projection
expression. The Console output is shown in Output 5.
Listing 8. Grouping elements and projecting into an anonymous type and how to
handle null values using the null-coalescing operator—see Output 5
List<Contact> contacts = Contact.SampleData();
var q = contacts.GroupBy( c => c.State ?? "state unknown", c => new { Title = c.FirstName + " " + c.LastName, Email = c.Email ?? "email address unknown" });
foreach (var group in q) { Console.WriteLine("State: {0}", group.Key); foreach (var element in group) Console.WriteLine(" {0} ({1})", element.Title, element.Email); }
|
Output 5.