The scenario: you have two related collections of objects, and you need to smush ‘em together into a collection of combined records. It’s easy to do with LINQ’s Join method, but Join can seem a little intimidating–just check out its declaration:
// yikes! public static IEnumerable Join<TOuter, TInner, TKey, TResult>( this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector )
It’s really not so bad, though. Here’s the breakdown:
- “this IEnumerable<TOuter> outer” what you’re joining from
- “IEnumerable<TInner> inner” what you’re joining to
- “Func<TOuter, TKey> outerKeySelector” an expression for how to match the ‘from’ records
- “Func<TInner, TKey> innerKeySelector” an expression for how to match the ‘to’ records
- “Func<TOuter, TInner, TResult> resultSelector” an expression for the joined result
Still sounds rough? Let’s look at an easy example:
class Person { public string Name; public string Occupation; } class Job { public string Name; public decimal Salary; } void Main() { var people = new[] { new Person { Name = "Adam", Occupation = "Blogger" }, new Person { Name = "Joe", Occupation = "Teacher" }, new Person { Name = "Hilary", Occupation = "Actress" } }; var jobs = new[] { new Job { Name = "Blogger", Salary = 0.0m }, new Job { Name = "Teacher", Salary = 100.0m }, new Job { Name = "Actress", Salary = 5000.0m } }; var salaryByPerson = people.Join( jobs, p => p.Occupation, j => j.Name, (p,j) => new { Person = p.Name, Salary = j.Salary }); foreach (var sbp in salaryByPerson) { Console.WriteLine("Person: {0}, Salary: {1}", sbp.Person, sbp.Salary.ToString("c")); } } /* Output Person: Adam, Salary: $0.00 Person: Joe, Salary: $100.00 Person: Hilary, Salary: $5,000.00 */
The Join in the above example is equivalent to SQL like this:
SELECT p.Name AS Person, j.Salary FROM people p JOIN jobs j ON p.Occupation=j.Name
Now you’ve got it, right? Yea!
