What's the best way to write [0..100] in C#?
Asked Answered
J

4

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;
    }
}
Jemina answered 11/10, 2008 at 16:46 Comment(0)
G
63

This is already in the framework: Enumerable.Range.

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

Gecko answered 11/10, 2008 at 16:49 Comment(4)
@Sam: Works for me, what's bad about it?Solenne
@Sam: Which one isn't working for you, and what are you getting?Gecko
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 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!Lizethlizette
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.Edette
J
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)
Jemina answered 11/10, 2008 at 16:47 Comment(1)
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.Etienne
J
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();
    }
}
Jemina answered 11/10, 2008 at 16:47 Comment(2)
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.Gecko
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.Jemina
J
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)
    }
}
Jemina answered 11/10, 2008 at 16:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.