views:

1827

answers:

4

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;
    }
}
+57  A: 

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
Bad link here Jon
Sam Mackrill
@Sam: Works for me, what's bad about it?
Kyle Cronin
@Sam: Which one isn't working for you, and what are you getting?
Jon Skeet
Well it didn't work, works now. I blame Microsoft.... sorry for the confusion
Sam Mackrill
IEnumerable<int> 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 iI 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!
drozzy
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
A: 

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
A: 

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
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
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
+5  A: 

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