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<T> 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!

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in LINQ. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://richarddingwall.name Richard Dingwall

    Nice, someone should get a project going for extra operators like these. Traverse() is another favourite of mine for flattening recursive hierarchies: http://social.msdn.microsoft.com/forums/en-US/linqprojectgeneral/thread/fe3d441d-1e49-4855-8ae8-60068b3ef741/

  • http://www.lostechies.com/members/jflanagan/default.aspx Joshua Flanagan

    I can see why you would hate the Enumerable.Repeat syntax, but not sure what would drive you to use it (except counting clock cycles).

    var oneToFour = ints.Concat(new[]{4});

    Not as pretty as Append, but definitely an improvement over Enumerable.Repeat, in my opinion.

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Josh

    Ha, yeah we use that way too especially in the overloads that take collections, but we just want to work with a single item. Concat, Union, Except, etc etc.

  • http://www.diogomafra.com.br/ Diogo Mafra

    In the first example you could use String.Join:
    String.Join(” “, source)

    I would like to have an extension method to verify if a string is null or empty ignoring spaces:
    (name == null || name.Trim().Length == 0)

  • http://geekswithblogs.net/WillSmith Will

    Alternate:
    Interesting, yet the example doesn’t seem like a good fit. As Diogo pointed out, you can simply use String.Join if the alternating value never changes.

    Append / Prepend
    I really like using the “params” keyword in situations like this. It allows me to call on a method more naturally and the compiler composes the collection (array) for me. Plus, in these examples, you would be able to append or prepend multiple values.

    e.g.
    public static IEnumerable Append( this IEnumerable source, params TSource[] elements )
    {
    return source.Concat( elements );
    }

    var start = new[] { 1, 2, 3 };
    var result = new[] { 1, 2, 3, 4, 5 };
    start.Append( 4, 5 ).ShouldHaveSameElements( result );

    However, I’ve never gone this far. I’ve been content with Joshua’s suggestion of new[]{x}.

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Will, @Diogo

    The real-life example is a split-join scenario, where the other joined piece is a list of custom items. It’s a template thing, transforming:

    “Hello [blank], today is [blank]” to “Hello Joe, today is Thursday”

  • http://www.jarrettmeyer.com Jarrett Meyer

    I find myself constantly wanting all of the array operations from Python to be available in .NET (without rewriting them myself).

  • Everett Muniz

    Thanks for sharing this. This is pretty incidental but I wonder if a clearer, more accurate name for Alternate would be Interlace.

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Everett

    That’s good too! I thought of Zip, but that was already taken :P I think “Splice” might be a good term too?

  • http://twitter.com/jalewis Joshua Alden Lewis

    I like that Alternate extension a lot. Have you thought about a version that would multiple list to be interwoven in an alternating fashion as opposed to just 2.