Beyond LINQ: Sequence Generation in C#

I’m taking a post off from the Paint Wars posts, but I think this one is worth it.

Many languages have nice syntactic sugar for creating a sequence of numbers. Usually, the syntax says something like:

The expression "1..5" expands to the list "1, 2, 3, 4, 5".

This syntax lets you do fun things like the below F# code:

for i in 1..5 do
    printfn "%d" i

Like a lot of syntactic sugar, this is simple but powerful. So, how can we get similar effects in C#? Hint:It’s very simple with extension methods.

public static IEnumerable<int> Through(this int startValue, int endValue)
{
    int offset;
    if (startValue < endValue)
    {
        offset = 1;
    }
    else
    {
        offset = -1;
    }

    for (int i = startValue; i != endValue + offset; i += offset)
    {
        yield return i;
    }
}

Now, we can write code like this in C#:

foreach(var i in 1.Through(5))
{
    Console.WriteLine(i);
}

Sure, the syntax is not quite as nice as 1..5, but it is not too bad, either.

Don’t forget to write extension methods on int, long, and all of the other numeric types to support this. Another obvious addition is an overload that takes an additional argument for "step" (eg. "1.Through(7, 2)" would produce produce the sequence "1, 3, 5, 7").

This entry was posted in Beyond LINQ, C#, Functional. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

4 Comments

  1. tofi9
    Posted May 5, 2009 at 10:51 am | Permalink

    You can also use: Enumerable.Range(1, 5).

  2. cmarinos
    Posted May 14, 2009 at 7:21 pm | Permalink

    Thanks for the comment about Enumerable.Range(). I didn’t realize this existed. I still like the fluent syntax of the .Through style, not to mention that Enumerable.Range() is a bit limited in it’s capabilities.

  3. Omer Mor
    Posted October 1, 2010 at 6:25 pm | Permalink

    Nice.
    The stepping overload could be also leveraged into a general extension method on IEnumerables:

    public static IEnumerable<int> Step(this IEnumerable<int> sequence, int step)
    {
    int currStep = 0;
    foreach(var i in sequence)
    {
    if (currStep==0)
    currStep = step;
    else
    {
    currStep -= 1;
    continue;
    }
    yield return i;
    }
    }

    And the usage would be:

    foreach(var i in 1.Through(5).Step(2))
    {
    Console.WriteLine(i);
    }

  4. Chris Marinos
    Posted October 2, 2010 at 8:26 pm | Permalink

    Omer-

    I like it. Although I might call it something like SkipEvery instead of Step so that it’s more consistent with the LINQ Skip method.

    Thanks for the comment!

    -Chris

One Trackback

Post a Comment

Your email is never published nor shared. Required fields are marked *

You may use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*
*