Reimplementing LINQ to Objects: Part 19 – Join

You might expect that as joining is such a fundamental concept in SQL, it would be a complex operation to both describe and implement in LINQ. Fortunately, nothing could be further from the truth… What is it? Join has a mere two overloads, with the familiar pattern of one taking a custom equality comparer and the other not: 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) public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(     this IEnumerable<TOuter> outer,     IEnumerable<TInner> inner,     Func<TOuter, TKey> … Continue reading Reimplementing LINQ to Objects: Part 19 – Join

Reimplementing LINQ to Objects: Part 18 – ToLookup

I’ve had a request to implement Join, which seems a perfectly reasonable operator to aim towards. However, it’s going to be an awful lot easier to implement if we write ToLookup first. That will also help with GroupBy and GroupJoin, later on. In the course of this post we’ll create a certain amount of infrastructure – some of which we may want to tweak later on. What is it? ToLookup has four overloads, with these signatures: public static ILookup<TKey, TSource> ToLookup<TSource, TKey>(     this IEnumerable<TSource> source,     Func<TSource, TKey> keySelector) public static ILookup<TKey, TSource> ToLookup<TSource, TKey>(     this IEnumerable<TSource> source,     Func<TSource, … Continue reading Reimplementing LINQ to Objects: Part 18 – ToLookup

Reimplementing LINQ to Objects: Part 17 – Except

I’m really pleased with this one. Six minutes ago (at the time of writing this), I tweeted about the Intersect blog post. I then started writing the tests and implementation for Except… and I’m now done. The tests are cut/paste/replace with a few tweaks – but it’s the implementation that I’m most pleased with. You’ll see what I mean later – it’s beautiful. What is it? Except is our final set operator, with the customary two overloads: public static IEnumerable<TSource> Except<TSource>(     this IEnumerable<TSource> first,     IEnumerable<TSource> second) public static IEnumerable<TSource> Except<TSource>(     this IEnumerable<TSource> first,     IEnumerable<TSource> second,     IEqualityComparer<TSource> comparer) … Continue reading Reimplementing LINQ to Objects: Part 17 – Except

Reimplementing LINQ to Objects: Part 16 – Intersect (and build fiddling)

Okay, this is more like it – after the dullness of Union, Intersect has a new pattern to offer… and one which we’ll come across repeatedly. First, however, I should explain some more changes I’ve made to the solution structure… Building the test assembly I’ve just had an irritating time sorting out something I thought I’d fixed this afternoon. Fed up of accidentally testing against the wrong implementation, my two project configurations ("Normal LINQ" and "Edulinq implementation") now target different libraries from the test project: only the "Normal LINQ" configuration refers to System.Core, and only the "Edulinq implementation" configuration refers … Continue reading Reimplementing LINQ to Objects: Part 16 – Intersect (and build fiddling)

Reimplementing LINQ to Objects: Part 15 – Union

I’m continuing the set-based operators with Union. I may even have a couple of hours tonight – possibly enough to finish off Intersect and Except as well… let’s see. What is it? Union is another extension method with two overloads; one taking an equality comparer and one just using the default: public static IEnumerable<TSource> Union<TSource>(     this IEnumerable<TSource> first,     IEnumerable<TSource> second) public static IEnumerable<TSource> Union<TSource>(     this IEnumerable<TSource> first,     IEnumerable<TSource> second,     IEqualityComparer<TSource> comparer) This "two overloads, one taking an equality comparer" pattern is familiar from Distinct; we’ll see that and Intersect and Except do exactly the same thing. Simply … Continue reading Reimplementing LINQ to Objects: Part 15 – Union

Reimplementing LINQ to Objects: Part 14 – Distinct

I’m going to implement the set-based operators next, starting with Distinct. What is it? Distinct has two overloads, which differ only in the simplest possible way: public static IEnumerable<TSource> Distinct<TSource>(     this IEnumerable<TSource> source) public static IEnumerable<TSource> Distinct<TSource>(     this IEnumerable<TSource> source,     IEqualityComparer<TSource> comparer) The point of the operator is straightforward: the result sequence contains the same items as the input sequence, but with the duplicates removed – so an input of { 0, 1, 3, 1, 5 } will give a result sequence of { 0, 1, 3, 5 } – the second occurrence of 1 is ignored. This time … Continue reading Reimplementing LINQ to Objects: Part 14 – Distinct

Reimplementing LINQ to Objects: Part 13 – Aggregate

EDIT: I’ve had to edit this quite a bit now that a second bug was discovered… basically my implementation of the first overload was completely broken 🙁 Last night’s tweet asking for suggestions around which operator to implement next resulted in a win for Aggregate, so here we go. What is it? Aggregate has three overloads, effectively allow two defaults: public static TSource Aggregate<TSource>(     this IEnumerable<TSource> source,     Func<TSource, TSource, TSource> func) public static TAccumulate Aggregate<TSource, TAccumulate>(     this IEnumerable<TSource> source,     TAccumulate seed,     Func<TAccumulate, TSource, TAccumulate> func) public static TResult Aggregate<TSource, TAccumulate, TResult>(     this IEnumerable<TSource> source,     TAccumulate seed, … Continue reading Reimplementing LINQ to Objects: Part 13 – Aggregate

Reimplementing LINQ to Objects: Part 12 – DefaultIfEmpty

After the masses of code required for all the permutations of First/Last/etc, DefaultIfEmpty is a bit of a relief. What is it? Even this simple operator has two overloads: public static IEnumerable<TSource> DefaultIfEmpty<TSource>(     this IEnumerable<TSource> source) public static IEnumerable<TSource> DefaultIfEmpty<TSource>(     this IEnumerable<TSource> source,     TSource defaultValue) The behaviour is very simple to describe: If the input sequence is empty, the result sequence has a single element in it, the default value. This is default(TSource) for the overload without an extra parameter, or the specified value otherwise. If the input sequence isn’t empty, the result sequence is the same as the … Continue reading Reimplementing LINQ to Objects: Part 12 – DefaultIfEmpty

Reimplementing LINQ to Objects: Part 11 – First/Single/Last and the …OrDefault versions

Today I’ve implemented six operators, each with two overloads. At first I expected the implementations to be very similar, but they’ve all turned out slightly differently… What are they? We’ve got three axes of permutation here: {First, Last, Single}, {with/without OrDefault }, {with/without a predicate}. That gives us these twelve signatures: public static TSource First<TSource>(     this IEnumerable<TSource> source) public static TSource First<TSource>(     this IEnumerable<TSource> source,     Func<TSource, bool> predicate) public static TSource FirstOrDefault<TSource>(     this IEnumerable<TSource> source) public static TSource FirstOrDefault<TSource>(     this IEnumerable<TSource> source,     Func<TSource, bool> predicate) public static TSource Last<TSource>(     this IEnumerable<TSource> source) public static TSource Last<TSource>(     this IEnumerable<TSource> … Continue reading Reimplementing LINQ to Objects: Part 11 – First/Single/Last and the …OrDefault versions

Reimplementing LINQ to Objects: Part 10 – Any and All

Another day, another blog post. I should emphasize that this rate of posting is likely to be short-lived… although if I get into the habit of writing a post on the morning commute when I go back to work after the Christmas holidays, I could keep ploughing through until we’re done. Anyway, today we have a pair of operators: Any and All. What are they? "Any" has two overloads; there’s only one for "All": public static bool Any<TSource>(     this IEnumerable<TSource> source) public static bool Any<TSource>(     this IEnumerable<TSource> source,     Func<TSource, bool> predicate) public static bool All<TSource>(     this IEnumerable<TSource> source,     Func<TSource, bool> predicate) … Continue reading Reimplementing LINQ to Objects: Part 10 – Any and All