Существует ли более короткая/более простая версия цикла for для чего-либо в x раз?
Обычно мы делаем что-то вроде цикла for или while со счетчиком:
for (int i = 0; i < 10; i++)
{
list.Add(GetRandomItem());
}
но иногда вы смешиваете границы. Вместо этого вы можете использовать цикл while, но если вы допустили ошибку, этот цикл будет бесконечным...
В Perl, например, я бы использовал более очевидный
for(1..10){
list->add(getRandomItem());
}
Есть ли что-то вроде "doitXtimes (10) {...}"?
Ответы
Ответ 1
Ну, вы можете легко написать свой собственный метод расширения:
public static void Times(this int count, Action action)
{
for (int i = 0; i < count; i++)
{
action();
}
}
Затем вы можете написать:
10.Times(() => list.Add(GetRandomItem()));
Я не уверен, что я действительно предлагаю вам это сделать, но это вариант. Я не считаю, что в этой области нет ничего подобного, хотя вы можете использовать Enumerable.Range
или Enumerable.Repeat
для создания ленивой последовательности соответствующей длины, которая может быть полезна в некоторых ситуациях.
Начиная с С# 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."));
Ответ 2
foreach (var i in Enumerable.Range(0, N))
{
// do something
}
Ответ 3
Можно создать IEnumerable
для Int32:
Enumerable.Range(0, 10);
Метод расширения ForEach также широко известен (хотя и не поставляется с .NET). Вы могли бы объединить два:
Enumerable.Range(0, 10).ForEach(index => ...);
Таким образом, ваш пример станет следующим:
Enumerable.Range(0, 10).ForEach(_ => list.Add(GetRandomItem()));
Ответ 4
Я вижу Jon Skeet избили меня до него, но этот вариант позволит вам передавать индекс в 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());
Ответ 5
Пример 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);
}
}
Ответ 6
while (i-->0) {
}
Вы упомянули, что в то время как цикл опасен, поскольку он может быть бесконечным - вышеупомянутая форма довольно проста и никогда не будет бесконечной. По крайней мере, ПОЛНОСТЬЮ бесконечно:)
Это удобно и коротко (короче любых других ответов) и будет выполняться ровно в я раз (поскольку декремент постфикса возвращает значение до декрементации).