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+

LINQ ToLookup Operator

Language-Integrated Query (LINQ) provides several methods that allow a sequence to be manipulated, filtered and grouped. ToLookup performs a grouping operation that results in a sequence of key / value pairs, where each value is another sequence.

ToLookup

In an earlier article I described how the values in a sequence can be grouped using Language-Integrated Query (LINQ). The grouping was performed using the GroupBy standard query operator and the group and into clauses of the query expression syntax. I have also described the ToDictionary method, which processes a sequence and extracts a set of key / value pairs.

The ToLookup extension method has similarities with both GroupBy and ToDictionary. When executed, it extracts a set of key / value pairs from the source sequence. Unlike ToDictionary, the generated keys need not be unique. Each element in the resultant collection is a generic Lookup object, which holds the key and a subsequence containing all of the items that matched the key. Unlike GroupBy, ToLookup does not use deferred execution.

Creating a Lookup Sequence

To demonstrate the use of ToLookup we need a test class to work with and a sequence containing some sample data. The class that we will use is shown below. It describes an employee with name, department and salary values.

public class Employee
{
    public string Name { get; set; }
    public string Department { get; set; }
    public int Salary { get; set; }

    public Employee(string name, string department, int salary)
    {
        Name = name;
        Department = department;
        Salary = salary;
    }

    public override string ToString()
    {
        return string.Format("{0} - {1} - {2}", Name, Department, Salary);
    }
}

For the sample data we need a sequence that contains employees in several departments and with varying salaries. The following list is suitable.

var employees = new List<Employee>();
employees.Add(new Employee("Bob", "IT", 30000));
employees.Add(new Employee("Dan", "Finance", 22000));
employees.Add(new Employee("Jim", "IT", 32000));
employees.Add(new Employee("Jon", "Finance", 24000));
employees.Add(new Employee("Ken", "Sales", 37000));
employees.Add(new Employee("Liz", "Finance", 24000));
employees.Add(new Employee("Mel", "IT", 40000));
employees.Add(new Employee("Sam", "Sales", 34000));
employees.Add(new Employee("Tim", "Finance", 45000));

We can now create a lookup sequence for the employees. The simplest version of the ToLookup method requires one parameter in addition to the variable that the extension method is acting upon. This accepts a Func delegate that extracts the key from each value, defining the groups that will be generated. In the following example we use the lambda expression, "e => e.Department" to group the values according to the department they work in.

var byDept = employees.ToLookup(e => e.Department);

foreach (var lookup in byDept)
{
    Console.WriteLine(lookup.Key);
    foreach (var element in lookup)
    {
        Console.WriteLine("  {0}", element);
    }
}

/* OUTPUT

IT
  Bob - IT - 30000
  Jim - IT - 32000
  Mel - IT - 40000
Finance
  Dan - Finance - 22000
  Jon - Finance - 24000
  Liz - Finance - 24000
  Tim - Finance - 45000
Sales
  Ken - Sales - 37000
  Sam - Sales - 34000

*/

As you can see, each unique department key value generates one element in the resultant sequence. The items that match the key are included in sequences linked to the key. Note the use of the Key property to obtain the key for output. We can also use the key with the collection's indexer to reference a single subsequence. The following totals the salaries of the IT department's employees.

var itSalary = byDept["IT"].Sum(e => e.Salary); // 102000

Adding an Element Selector

Often you will wish to create a sequence of lookups where the values are projections of the original elements. You can achieve this using an element selector. This is a second lambda expression that performs an operation on each source value. In the example below, the element selector extracts only the name from each employee.

var byDept = employees.ToLookup(e => e.Department, e => e.Name);

/* RESULTS

IT
  Bob
  Jim
  Mel
Finance
  Dan
  Jon
  Liz
  Tim
Sales
  Ken
  Sam

*/
22 May 2011