15

I'm trying to think of clever, clear, and simple ways to write code that describes the sequence of integers in a given range.

Here's an example:

IEnumerable<int> EnumerateIntegerRange(int from, int to)
{
    for (int i = from; i <= to; i++)
    {
        yield return i;
    }
}
Jay Bazuzi
  • 45,157
  • 15
  • 111
  • 168

4 Answers4

63

This is already in the framework: Enumerable.Range.

For other types, you might be interested in the range classes in my MiscUtil library.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 3
    @Sam: Works for me, what's bad about it? – Kyle Cronin Jul 13 '09 at 17:14
  • 2
    @Sam: Which one isn't working for you, and what are you getting? – Jon Skeet Jul 13 '09 at 18:10
  • IEnumerable squares = Enumerable.Range(1, 10).Select(x => x * x); foreach (int num in squares) { Console.WriteLine(num); } versus (in python): for i in range(10): print i I love how compiled languages bend over backwards to make simple things very complicated. It's like the simpler it is - the harder it is to code! – Andriy Drozdyuk Mar 16 '10 at 15:11
  • 1
    Huh? In C# it can be `foreach(var i in Enumerable.Range(1, 10)) Console.WriteLine(i * i);` ... The names of the range and print functions are longer, and Range needs a start parameter. No variables other than i, no lambdas. – Jeffrey Hantin Oct 15 '10 at 02:59
7

Alternately, a fluent interface from extension methods:

public static IEnumerable<int> To(this int start, int end)
{
    return start.To(end, i => i + 1);
}

public static IEnumerable<int> To(this int start, int end, Func<int, int> next)
{
    int current = start;
    while (current < end)
    {
        yield return current;
        current = next(current);
    }
}

used like:

1.To(100)
Jay Bazuzi
  • 45,157
  • 15
  • 111
  • 168
  • Personally, I like the way the extension method reads better. Although, I do have a bit of a soft side for extension methods(I implemented them for VB). I never understood why the C# folks didn't make Range an extension method in the first place. – Scott Wisniewski Dec 29 '08 at 20:12
0

Here's an idea that lets a range class work with both things that are discrete and those which are not:

class Range<T> where T: IComparable<T>
{
    public T From { get; set; }
    public T To { get; set; }

    public Range(T from, T to) { this.From = from; this.To = to; }

    public IEnumerable<T> Enumerate(Func<T, T> next)
    {
        for (T t = this.From; t.CompareTo(this.To) < 0; t = next(t))
        {
            yield return t;
        }
    }

    static void Example()
    {
        new Range<int> (0, 100).Enumerate(i => i+1)
    }
}
Jay Bazuzi
  • 45,157
  • 15
  • 111
  • 168
0

And if you think that supplying the enumerator each time is annoying, here's a derived class:

class EnumerableRange<T> : Range<T>, IEnumerable<T>
    where T : IComparable<T>
{
    readonly Func<T, T> _next;
    public EnumerableRange(T from, T to, Func<T, T> next)
        : base(from, to)
    {
        this._next = next;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return Enumerate(this._next).GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}
Jay Bazuzi
  • 45,157
  • 15
  • 111
  • 168
  • 1
    I've found it provides better separation to have a Range class and a distinct RangeIterator class. Aside from anything else, it means your Range can be immutable and sealed, which is nice. The version in MiscUtil has various methods (extension and otherwise) to go between the two. – Jon Skeet Oct 13 '08 at 06:28
  • Yeah, I saw the one in MiscUtil. My Range could be immutable; the only reason for mutability, for me, is that it allows C# object initializers. I probably should have gone for the immutability. – Jay Bazuzi Oct 13 '08 at 12:54