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.

Using an Alternative Comparer

As with other standard query operators that compare values, you can substitute an alternative comparer. If no comparer is specified, the default comparer for the key type is used. We can see this in the following sample code. Here a new employee has been added but the department has been incorrectly added in lower case. As the default comparer for strings is case-sensitive, the ToLookup method treats "it" and "IT" as different keys.

employees.Add(new Employee("Ian", "it", 18000));
var byDept = employees.ToLookup(e => e.Department);

/* RESULTS

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
it
  Ian - it - 18000

*/

To fix the above problem we can supply an alternative comparer. Any comparer that implements IEqualityComparer<T>, where T is the type of the key, can be used. In this case we use a case-insensitive string comparer to combine the two "IT" subsequences.

var byDeptNoCase = employees.ToLookup(e => e.Department, StringComparer.OrdinalIgnoreCase);

/* RESULTS

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

*/

We can also use an element selector and an alternative comparer together. The element selector must be the second argument and the comparer the third.

var byDeptNoCaseNames = employees.ToLookup(
    e => e.Department, e => e.Name, StringComparer.OrdinalIgnoreCase);

/* RESULTS

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

*/

Projecting the Lookup Sequence

As we have seen, we can refer to each child sequence in a lookup collection by referencing its key. We can also perform all of the standard LINQ operations over the entire sequence or individual subsequences. The final example shows this by first using ToLookup to group the employees by department. Next, the main sequence is projected into a sequence of an anonymous type, where each item contains the department name and the sum of the salaries of the employees in that department.

var byDept = employees.ToLookup(e => e.Department, StringComparer.OrdinalIgnoreCase);
var deptSalaries = byDept.Select(d =>
    new { Department = d.Key, TotalSalary = d.Sum(e => e.Salary) });

/* RESULTS

{ Department = IT, TotalSalary = 120000 }
{ Department = Finance, TotalSalary = 115000 }
{ Department = Sales, TotalSalary = 71000 }

*/
22 May 2011