More missing LINQ operators


Continuing an old post on missing LINQ operators, the wonders of extension methods allow us as developers to fill potential holes in LINQ operators.  Whether it’s a Zip method (now included in .NET 4.0), or better methods for IComparer-based operators, I find myself adding more and more helpful LINQ operators, I wish were already in the framework.

Alternate

Do you ever want to weave two collections together, like shuffling a deck of cards?  Well I know I do!  Suppose we have this collection:

[1, 3, 5]

And this collection:

[2, 4, 6]

I’d like to create new collection that is the alternating items from the first and second list:

[1, 2, 3, 4, 5, 6]

Here’s the code to do it:

public static IEnumerable<TSource> Alternate<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second)
{
    using (IEnumerator<TSource> e1 = first.GetEnumerator())
    using (IEnumerator<TSource> e2 = second.GetEnumerator())
        while (e1.MoveNext() && e2.MoveNext())
        {
            yield return e1.Current;
            yield return e2.Current;
        }
}

Very simple, I iterate both enumerables at the same time, yielding the first, then second collection’s current item.  So how is this useful?  How about this action:

[Test]
public void Word_play()
{
    var source = new[] {"The", "quick", "brown", "fox"};

    var result = source.Alternate(Spaces()).Aggregate(string.Empty, (a, b) => a + b);

    result.ShouldEqual("The quick brown fox ");
}

private IEnumerable<string> Spaces()
{
    while (true)
        yield return " ";
}

I cheated a little bit with an infinite sequence (the Spaces() method), but I found this method useful when I had to split, then reconstruct new sequences of strings.

Append

I really hate this syntax:

[Test]
public void Bad_concat_method()
{
    var ints = new[] {1, 2, 3};

    var oneToFour = ints.Concat(Enumerable.Repeat(4, 1));

    CollectionAssert.AreEqual(new[] { 1, 2, 3, 4 }, oneToFour.ToArray());
}

I want to just stick an item on the end of an existing collection, but I have to use this arcane Enumerable.Repeat method to do so.  Instead, let’s create an operator that lets us tack an item on to the end of a collection:

public static IEnumerable<TSource> Append<TSource>(this IEnumerable<TSource> source, TSource element)
{
    using (IEnumerator<TSource> e1 = source.GetEnumerator())
        while (e1.MoveNext())
            yield return e1.Current;

    yield return element;
}

Now our code becomes much easier to understand:

[Test]
public void Easier_concat_with_append()
{
    var ints = new[] {1, 2, 3};

    var oneToFour = ints.Append(4);

    CollectionAssert.AreEqual(new[] { 1, 2, 3, 4 }, oneToFour.ToArray());
}

Prepend

Append wouldn’t be complete without the converse, Prepend, now would it?

public static IEnumerable<TSource> Prepend<TSource>(this IEnumerable<TSource> source, TSource element)
{
    yield return element;

    using (IEnumerator<TSource> e1 = source.GetEnumerator())
        while (e1.MoveNext())
            yield return e1.Current;
}

Now putting something on the beginning of a list is easier as well:

[Test]
public void Easier_concat_with_prepend()
{
    var ints = new[] {1, 2, 3};

    var zeroToThree = ints.Prepend(0);

    CollectionAssert.AreEqual(new[] { 0, 1, 2, 3 }, zeroToThree.ToArray());
}

Much more readable.  I have a few more around replacing the IEqualityComparer overloads, but those are a little bit more esoteric in their examples of crazy set-based logic.  What’s really cool about all these methods is they still allow all sorts of fun chaining, allowing me to create very terse chains of operations on lists, with what would have taken a bazillion cryptic for..each loops.  Cool stuff!

Thanks Arkansas!