是否有更短/更简单的for循环版本到x次?

时间:2010-10-14 11:00:01

标签: c# .net

通常我们使用计数器执行类似for或while循环的操作:

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

但有时你会混淆边界。你可以使用while循环,但如果你犯了一个错误,这个循环是无限的...

在Perl例如,我会使用更明显的

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

是否有类似“doitXtimes(10){...}”的内容?

7 个答案:

答案 0 :(得分:62)

您可以轻松编写自己的扩展方法:

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

然后你可以写:

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

我不确定我是否真的建议你,但这是一个选择。虽然你可以使用Enumerable.RangeEnumerable.Repeat创建一个适当长度的懒惰序列,但我不相信框架中有类似的东西,这在某些情况下很有用。


从C#6开始,您仍然可以方便地访问静态方法而无需创建扩展方法,使用using static指令进行导入。例如:

// 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();
        }
    }
}

然后当你想要使用它时:

using static LoopUtilities;

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

答案 1 :(得分:40)

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

答案 2 :(得分:33)

可以创建IEnumerable Int32:

Enumerable.Range(0, 10);

ForEach扩展方法也广为人知(尽管未附带.NET)。你可以将两者结合起来:

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

所以你的例子会变成:

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

答案 3 :(得分:11)

我看到Jon Skeet beat me to it,但是此变体将允许您在每次运行时将索引传递给Action:

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

并称之为:

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

答案 4 :(得分:4)

示例1

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

示例2

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

示例3

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

Loop class&amp;扩展

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);
    }

}

答案 5 :(得分:2)

while (i-- > 0) {

}

你提到虽然循环是危险的,因为它可能是无限的 - 上面的形式非常简单,永远不会是无限的。至少完全无限:)

它方便而短(比任何其他答案都短)并且将完全 i 次运行(因为postfix减量在递减之前返回值)。

答案 6 :(得分:2)

仍然缺少一种方法:

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

其中T是GetRandomItem()返回的类型