using System; using System.Collections.Generic; using System.Text; namespace System.Linq { public static partial class Enumerable { public static IEnumerable Join (this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func resultSelector) { if (outer == null) throw new ArgumentNullException ("outer"); if (inner == null) throw new ArgumentNullException ("inner"); if (outerKeySelector == null) throw new ArgumentNullException ("outerKeySelector"); if (innerKeySelector == null) throw new ArgumentNullException ("innerKeySelector"); if (resultSelector == null) throw new ArgumentNullException ("resultSelector"); ILookup lookup = inner.ToLookup (innerKeySelector); // We can use LINQ to write LINQ! A SelectMany-style query over a lookup is the easiest way to // implement a Join (see page 344, C# 3.0 in a Nutshell). return from outerItem in outer from innerItem in lookup [outerKeySelector (outerItem)] select resultSelector (outerItem, innerItem); } public static IEnumerable GroupJoin ( this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func, TResult> resultSelector) { if (outer == null) throw new ArgumentNullException ("outer"); if (inner == null) throw new ArgumentNullException ("inner"); if (outerKeySelector == null) throw new ArgumentNullException ("outerKeySelector"); if (innerKeySelector == null) throw new ArgumentNullException ("innerKeySelector"); if (resultSelector == null) throw new ArgumentNullException ("resultSelector"); ILookup lookup = inner.ToLookup (innerKeySelector); // We won't make this harder than it needs to be - a GroupJoin is just a projection over a lookup! return from outerItem in outer select resultSelector (outerItem, lookup [outerKeySelector (outerItem)]); } } }