BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

LINQ
.NET 3.5+

Grouping on Multiple Properties with LINQ

LINQ allows queries to be executed that include grouping. The GroupBy query operator and the group clause both allow grouping using a single key selector. When it is necessary to group by multiple keys, the selector must include an expression.

Grouping Data

In the LINQ to Objects tutorial I described the GroupBy standard query operator and the group clause of the query expression syntax. Each of these permits grouping of collections that support the IEnumerable<T> interface. In that article I briefly explained that you can create groups that are based upon multiple fields, properties or expressions using an anonymous type in the key selector. In this article I will give some examples.

Sample Data

To demonstrate grouping on multiple properties we need a sample class. The class that we will use will include a product name, category and sub-category. The code for the class, which should be included in a console application, is as follows:

public class Product
{
    public string Name { get; set; }
    public string Category { get; set; }
    public string Subcategory { get; set; }

    public Product(string category, string subcategory, string name)
    {
        Category = category;
        Subcategory = subcategory;
        Name = name;
    }
}

We also need some sample data that includes multiple categories and subcategories. To create this data, add the following code to the Main method:

var products = new List<Product>
{
    new Product("Food", "Fruit", "Apple"),
    new Product("Food", "Fruit", "Banana"),
    new Product("Food", "Fruit", "Orange"),
    new Product("Food", "Vegetables", "Carrot"),
    new Product("Food", "Vegetables", "Pea"),
    new Product("Drink", "Soft Drink", "Orange Juice"),
    new Product("Drink", "Soft Drink", "Lemonade"),
    new Product("Drink", "Alcoholic", "Bitter"),
    new Product("Drink", "Alcoholic", "Lager"),
    new Product("Drink", "Alcoholic", "Vodka")
};

If you wish to group by both the category and the subcategory, you can combine the two values using an expression or an anonymous type for the key selector. In the following example an anonymous type is used.

var grouped = products.GroupBy(p => new { p.Category, p.Subcategory });

To show the results you must use two loops. An outer loop will output the group keys and a nested loop will show the products in each group:

foreach (var group in grouped)
{
    Console.WriteLine(group.Key);
    foreach (var product in group)
    {
        Console.WriteLine("  {0}", product.Name);
    }
}

/* OUTPUT

{ Category = Food, Subcategory = Fruit }
  Apple
  Banana
  Orange
{ Category = Food, Subcategory = Vegetables }
  Carrot
  Pea
{ Category = Drink, Subcategory = Soft Drink }
  Orange Juice
  Lemonade
{ Category = Drink, Subcategory = Alcoholic }
  Bitter
  Lager
  Vodka

*/

When outputting to the console in this manner, or for logging to a text file, it would be more useful to use an expression for the grouping. This can make the category names easier to read. For example:

var grouped = products.GroupBy(p => string.Format("{0}/{1}", p.Category, p.Subcategory));

/* OUTPUT

Food/Fruit
  Apple
  Banana
  Orange
Food/Vegetables
  Carrot
  Pea
Drink/Soft Drink
  Orange Juice
  Lemonade
Drink/Alcoholic
  Bitter
  Lager
  Vodka

*/

As you may expect, both of the above grouping queries can be represented using the query expression syntax. The equivalent queries are:

var grouped =
    from p in products
    group p by new { p.Category, p.Subcategory };

var grouped =
    from p in products
    group p by string.Format("{0}/{1}", p.Category, p.Subcategory);
31 July 2010