![LINQ](icons/Linq.png)
.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