Is there a shorter/simpler version of the for loop to anything x times?

C#.Net

C# Problem Overview


Usually we do something like a for or while loop with a counter:

for (int i = 0; i < 10; i++)
{
    list.Add(GetRandomItem());
}

but sometimes you mix up with boundaries. You could use a while loop instead, but if you make a mistake this loop is infinite...

In Perl for example I would use the more obvious

for(1..10){
    list->add(getRandomItem());
}

Is there something like doitXtimes(10){...}?

C# Solutions


Solution 1 - C#

Well you can easily write your own extension method:

public static void Times(this int count, Action action)
{
    for (int i = 0; i < count; i++)
    {
        action();
    }
}

Then you can write:

10.Times(() => list.Add(GetRandomItem()));

I'm not sure I'd actually suggest that you do that, but it's an option. I don't believe there's anything like that in the framework, although you can use Enumerable.Range or Enumerable.Repeat to create a lazy sequence of an appropriate length, which can be useful in some situations.


As of C# 6, you can still access a static method conveniently without creating an extension method, using a using static directive to import it. For example:

// Normally in a namespace, of course.
public class LoopUtilities
{
    public static void Repeat(int count, Action action)
    {
	    for (int i = 0; i < count; i++)
	    {
		    action();
	    }
    }
}

Then when you want to use it:

using static LoopUtilities;

// Class declaration etc, then:
Repeat(5, () => Console.WriteLine("Hello."));

Solution 2 - C#

foreach (var i in Enumerable.Range(0, N))
{
    // do something
}

Solution 3 - C#

One can create an IEnumerable of Int32:

Enumerable.Range(0, 10);

The ForEach extension method is also widely known (although not shipped with .NET). You could combine the two:

Enumerable.Range(0, 10).ForEach(index => ...);

So your example would become:

Enumerable.Range(0, 10).ForEach(_ => list.Add(GetRandomItem()));

Solution 4 - C#

I see Jon Skeet beat me to it, but this variation will allow you to pass the index to the Action each time it is run:

public static class IntegerExtensions
{
  public static void TimesWithIndex(this int count, Action<int> action)
  {
     for (int i = 0; i < count; i++)
        action(i);
  }
}

And call it like this:

10.TimesWithIndex((i) =>
            obj[i].DoSomething());

Solution 5 - C#

while (i-- > 0) {

}

You mentioned that while loop is dangerous as it may be infinite - the above form is pretty simple and will never be infinite. At least TOTALLY infinite :)

It's convenient and short (shorter than any of the other answers) and will run exactly i times (because postfix decrement returns value before decrementation).

Solution 6 - C#

There's still one way missing:

List<T> list = System.Linq.Enumerable.Range(0, 10).Select(_ => GetRandomItem()).ToList();

Where T is the type returned by GetRandomItem()

Solution 7 - C#

Example 1

            var loop = new Loop(50);
            foreach(var index loop) {
                // do something
            }

Example 2

            foreach(var index in 50.Times().Start(1).Step(-1)) {
                // do something
            }

Example 3

            var loop = 20.Times();
            while (loop.Do) {
                // do something
            }

Loop class & extension

public class Loop : IEnumerable<int> {

    readonly int times = 0;
    int start = 0;
    int step = 1;
    IEnumerator<int> e;

    public Loop (int times, int start = 0, int step = 1) {
        this.times = times < 0? 0-times : times;
        this.start = start;
        this.step = step;
    }
    
    public Loop Start(int value) {
        this.start = value;
        return this;
    }

    public Loop Step(int value) {
        this.step = value;
        return this;
    }
    
    public bool Do {
        get {
            if (this.e.IsNull()) {
                this.e = this.GetEnumerator();
            }
            if (this.e.MoveNext()) {
                return true;
            }
            else {
                this.e.Dispose();
                this.e = null;
                return false;
            }
        }
    }

    IEnumerator IEnumerable.GetEnumerator() {
        return this.GetEnumerator();
    }
    public IEnumerator<int> GetEnumerator() {
        int count = times;
        int value = start;
        while (count != 0) {
            yield return value;
            try {
                value += step;
            }
            catch (OverflowException) {
                break;
            }
            --count;
        }
        yield break;
    }
}

public static class IntLoopExtension {

    public static Loop Times (this int self) {
        return new Loop (self);
    }

}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmbxView Question on Stackoverflow
Solution 1 - C#Jon SkeetView Answer on Stackoverflow
Solution 2 - C#GrozzView Answer on Stackoverflow
Solution 3 - C#Paul RuaneView Answer on Stackoverflow
Solution 4 - C#Alex BaranoskyView Answer on Stackoverflow
Solution 5 - C#aaimnrView Answer on Stackoverflow
Solution 6 - C#A. MorelView Answer on Stackoverflow
Solution 7 - C#ddurView Answer on Stackoverflow