Как стать автором
Обновить

Комментарии 24

А как же вариант для C# с Linq?
// По возрастанию
foreach (int value in Enumerable.Range(1, 10))
{
    ...
}
// По обыванию
foreach (int value in Enumerable.Range(1, 10).Reverse())
{
    ...
}

И для Step, наверное, можно .Where() добавить
Я согласен, что это не совсем тот цикл, но есть ли смысл привязываться к for, если есть другие варианты?
Ну я подумывал о чем-то вроде автоматического перекодировщика
Нужен универсальный код, который годится и для положительного, и для отрицательного шага!

И часто у вас попадаются циклы, которые идут в обе стороны?

Чем плохо решение оставить код на VBA?
Если бы действительно требовалось что-то кроме VBA, то изначально бы подключался Python, JScript и т.п. в 5 строк VBA.
Тем, что это не решение)
статья из раздела «хабр, который мы заслужили».
наверное эквивалент for все-таки будет не for(i=lower;i<upper+1;i+=step);, а что-то вроде for(i=start;i!=end;i+=step);
если step не укладывается целое число раз в диапазон start..end, то из цикла никогда не выйдем!
ЕМНИП, в циклах Pascal нет step. Там используются выражения for to и for downto для циклов с увеличением и уменьшением счётчика на единицу, соответственно.
А заменить можно, например, так:
for (i = Lower, j = 0; j <= (Upper - Lower) / Step; i += Step, j++)
Кстати да, в Pascal так и было, это МИП)) Ваш код не сработает, если Upper<Lower
Если Upper < Lower, то и Step должен быть отрицательный. Иначе и в VB цикл FOR не сработает.
Я бы предложил почитать учебник. Без вариантов.
НЛО прилетело и опубликовало эту надпись здесь
Не стойте на пути у прогресса)
НЛО прилетело и опубликовало эту надпись здесь

Изначально задать начало и коэффициент плюс если конец больше или минус один если меньше, после чего в цикле индекса от нуля до модуля разности начального и конечного значений получать значение как начало плюс индекс умноженный на коэффициент.

for i = Lower to Upper step Step
Она универсальна в том смысле, что может ехать как снизу вверх, так и сверху вниз. Ее можно использовать и если Step>0, и если Step<0.

Но ведь если Step отрицательный, надо и Lower c Upper местами поменять, а не просто задать значение Step. А вы почему-то пытаетесь на других языках привести к форме, когда можно только Step поменять.


Пример из документации


For indexB = 20 To 1 Step -3

Для Питона надо ```python
range(b, a, -1)


> Оказывается, цикл с использованием range на Python также не позволяет двигаться от большего значения к меньшему, range(b, a) при b>a задает просто пустой диапазон.

1) В питоне range(start, end, step) прекрасно работает с отрицательным шагом.
2) В бейсике цикл не lower to upper, а тоже start to end. Не вводите себя и других в заблуждение.


3) В бейсике и паскале интервалы закрытые (насколько это возможно), в питоне и всех сях (плюсах, шарпе) — полуоткрытые, но в сях можно сделать и закрытыми.
И это принципиальная разница, идеологическая.


По поводу перекодирования.
Начните с того, что существуют несколько разных сценариев использования цикла. Хоть у них и один синтаксис. Соответственно, и перекодирование будет разным (если вы хотите получить человекочитаемый код).


  • for i = start to finish
    = на питоне range(start, finish+1)
    = на сях for(i = start; i <= finish; ++i)
    Это обычный перебор индексов.
  • for i = finish to start step -1
    = на питоне range(finish, start-1, -1)
    = на сях for(i = finish; i >= start; --i)
    Это перебор в обратном направлении
  • Перебор в прямом или обратном направлении в зависимости от флага
  • Перебор в прямом направлении с произвольным шагом
  • Перебор с произвольным шагом в любом направлении

Наверняка в бейсике эти три последних сценария будут сопровождаться какими-то хитростями по вычислению границ цикла — в том числе, из-за работы с закрытыми интервалами.
При переводе на си или питон можно сверху навертеть переход от закрытого к открытому интервалу, но эти правки просто будут уничтожать друг друга. Почему бы не сократить?


В общем виде, на питоне это всего лишь range(start, finish + step, step).
На сях — предлагаю не вертеть арифметические формулы со знаком, а написать БУКВАЛЬНО.


for(
    i = start;
    (step > 0) ? i <= finish : (step < 0) ? i >= finish : false;
    i += step
)

Да, кстати. На сях вас ещё ждут весёлые игры с беззнаковыми целыми. После бейсика это будет больно.


Поэтому не просто перекодируйте вашу программу, а в каждом месте крепко задумывайтесь: что вы тут делаете, и может быть, не надо перетаскивать идиомы бейсика в другой язык со своими идиомами и особенностями.


На питоне, например, вместо игр с индексами рекомендуется перебирать прямо элементы массива. А если индексы тоже нужны, то надо перебирать по пронумерованным элементам


for x in array:
    print(x)

for i, x in enumerate(array):
    print(i, '=>', x)

# вместо
for i in range(len(array)):
    print(i, '=>', array[i])

Очевидно, что автоматически перекодировать бейсик в питон с учётом всего этого — будет сложновато, мягко говоря.

Вот код, который вы ищете, для случая когда Step отрицательный.


for (i = Upper; i >= Lower; i += Step)

Хотя в большинстве случаев Step положительный, и делают вот так.


for (i = Upper; i >= Lower; i -= Step)
Если уж хочется по простому переписать, то вот вам вариант:

public sealed class Loop
{
    public static void ForNext(int start, int end, int step, Action<int> action) 
    {
        int ind = start;

        while(step > 0 ? ind <= end : ind >= end)
        {
            action(ind);
            ind += step;
        }
            
    }
}
class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("begin up loop");

        var s = "=>";
        Loop.ForNext(1, 6, 2, (n) => Console.WriteLine(s+n));

        Console.WriteLine("begin down loop");

        s = "<=";
        Loop.ForNext(5, -2, -2, (n) => Console.WriteLine(s+n));

        Console.ReadLine();

    }
}

Выведет:
begin up loop
=>1
=>3
=>5
begin down loop
<=5
<=3
<=1
<=-1
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации