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

问题描述 投票:48回答:7

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

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

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

以Perl为例,我会使用更明显的

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

有没有像“doitXtimes(10){...}”这样的东西?

c# .net
7个回答
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."));

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

33
投票

可以创建一个Int32的IEnumerable

Enumerable.Range(0, 10);

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

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

所以你的例子将成为:

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

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

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

循环类和扩展

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

}

2
投票
while (i-- > 0) {

}

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

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


2
投票

仍有一种方法缺失:

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

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

© www.soinside.com 2019 - 2024. All rights reserved.