{TOC}
| Namespace: | System.Linq |
| Assembly: | System.Core.dll |
| Extends: | IEnumerable<T> |
Back to
Standard Query Operator IndexEditIntroduction
The Join operator performs an inner join of two sequences based on matching keys extracted from the elements.
(if you need outer join behaviour, where outer elements with no matching inner elements are also returned, see
Outer Join Sample.
EditMethod Signatures
// 1 - Join with another source
public static IEnumerable<TResult> 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)
// New in January CTP
// 2 - Join with another source, use custom comparer function for equality testing of keys.
public static IEnumerable<TResult> 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,
IEqualityComparer<TKey> comparer)EditExceptions
Throws an ArgumentNullException if
outer,
inner,
outerKeySelector,
innerKeySelector or
resultSelector are null.
EditPseudo-code
Overload 1
If
outer is null, throw an ArgumentNullException.
If
inner is null, throw an ArgumentNullException.
If
outerKeySelector is null, throw an ArgumentNullException.
If
innerKeySelector is null, throw an ArgumentNullException.
If
resultSelector is null, throw an ArgumentNullException.
(Create a lookup table of groups based on the
inner sequence key's evaluated by the
innerKeySelector call it "inner groupings".)
Iterate the
inner sequence.
Determine the key of this element as the result innerKeySelector(current element).
If this key is already grouped.
Add the current element to that group.
else, create a group for this key value.
Add the current element to the new group group.
(Match inner and outer groups and return results)
Iterate the
outer sequence.
Find the grouping in "inner groupings" that matches the result of outerKeySelector(current element) call it "element group" using the EqualityComparer<TSource>.Default comparer function.
Iterate the "element group".
Return resultSelector(current element in "element group"). (Resume execution from here when the next element is requested).
Overload 2
If
outer is null, throw an ArgumentNullException.
If
inner is null, throw an ArgumentNullException.
If
outerKeySelector is null, throw an ArgumentNullException.
If
innerKeySelector is null, throw an ArgumentNullException.
If
resultSelector is null, throw an ArgumentNullException.
If
comparer is null, default to
EqualityComparer<TSource>.Default;
(Create a lookup table of groups based on the
inner sequence key's evaluated by the
innerKeySelector call it "inner groupings".)
Iterate the
inner sequence.
Determine the key of this element as the result innerKeySelector(current element).
If this key is already grouped.
Add the current element to that group.
else, create a group for this key value.
Add the current element to the new group group.
(Match inner and outer groups and return results)
Iterate the
outer sequence.
Find the grouping in "inner groupings" that matches the result of outerKeySelector(current element) call it "element group" using the comparer function.
Iterate the "element group".
Return resultSelector(current element in "element group"). (Resume execution from here when the next element is requested).
Note: By this pseudo-code you can see that if there are no matching inner elements for a given outer element key, then no elements are yielded for that outer element. If you want to yield a result for non-matched outer elements, see
Outer Join Sample.
EditLoop count
1 full loop of the
inner sequence. Looping over the
outer sequence happens as the result is iterated. This operator implements the standard
deferred execution iterator pattern. This means, no looping will occur until the result is iterated over.
EditCode Samples
public static void JoinSimpleExample()
{
var customers = new List<Customer>() {
new Customer {Key = 1, Name = "Gottshall" },
new Customer {Key = 2, Name = "Valdes" },
new Customer {Key = 3, Name = "Gauwain" },
new Customer {Key = 4, Name = "Deane" },
new Customer {Key = 5, Name = "Zeeman" }
};
var orders = new List<Order>() {
new Order {Key = 1, OrderNumber = "Order 1" },
new Order {Key = 1, OrderNumber = "Order 2" },
new Order {Key = 4, OrderNumber = "Order 3" },
new Order {Key = 4, OrderNumber = "Order 4" },
new Order {Key = 5, OrderNumber = "Order 5" },
};
var q = from c in customers
join o in orders on c.Key equals o.Key
select new {c.Name, o.OrderNumber};
foreach (var i in q) {
Console.WriteLine("Customer: {0} Order Number: {1}",
i.Name.PadRight(11, ' '), i.OrderNumber);
}
Console.ReadLine();
}
public class Customer
{
public int Key;
public string Name;
}
public class Order
{
public int Key;
public string OrderNumber;
}Customer: Gottshall Order Number: Order 1
Customer: Gottshall Order Number: Order 2
Customer: Deane Order Number: Order 3
Customer: Deane Order Number: Order 4
Customer: Zeeman Order Number: Order 5