Как изменить порядок в цикле FOR

У меня есть простой оператор FOR, подобный этому:

var num = 10,
    reverse = false;

for(i=0;i<num;i++){
    console.log(i);
}

когда reverse является ложным, я хочу, чтобы он возвращал что-то вроде [0,1,2,3,4,5,6,7,8,9]

но если reverse истинно, он должен вернуть [9,8,7,6,5,4,3,2,1,0]

Каков наиболее эффективный способ получить этот результат, не проверяя каждый раз, является ли reverse истинным или ложным внутри цикла?

Я не хочу этого делать:

var num = 10,
    reverse = false;

for(i=0;i<num;i++){
    if(reverse) console.log(num-i)
    else console.log(i)
}

Я хотел бы проверить реверс только один раз вне цикла.


person Raspo    schedule 27.08.2010    source источник
comment
Что вы на самом деле пытаетесь сделать? Потому что, если он создает массив или цикл в массиве, всегда есть функция javascript, обратная w3schools. com / jsref / jsref_reverse.asp, который вы можете вызвать   -  person CaffGeek    schedule 27.08.2010
comment
w3schools не так хорош. Ознакомьтесь с w3fools.   -  person DwB    schedule 03.02.2012


Ответы (11)


var num = 10,
reverse = false;

if(!reverse) for( var i=0;i<num;i++) log(i);
else         while(num-- )      log(num);

   // to avoid duplication if the code gets long
function log( num ) { console.log( num ); }

РЕДАКТИРОВАТЬ:

Как отмечено в комментариях ниже, если i не объявлен где-либо еще и вы не собираетесь делать его глобальным, то объявите его с другими объявленными вами переменными.

И если вы не хотите изменять значение num, сначала назначьте его i.

var num = 10,
reverse = false,
i;

if(!reverse) for(var i=0;i<num;i++) log(i);   // Count up
else         {var i=num; while(i--) log(i);}  // Count down

function log( num ) { console.log( num ); }
person user113716    schedule 27.08.2010
comment
Хороший. Я собирался предложить for(i = num; i--;) log(i);, но, похоже, консенсус таков ваш метод самый быстрый. - person palswim; 27.08.2010
comment
На операцию: имейте в виду, что num будет изменен при печати в обратном порядке, поэтому обязательно сделайте копию исходного значения, если вы планируете использовать это значение в будущем. - person Cristian Sanchez; 27.08.2010
comment
@ Дэниел - Совершенно верно. Если это вас беспокоит, вот быстрая замена оператора else: else{i=num;while(i--)log(i)}; - person user113716; 27.08.2010
comment
не забудьте где-нибудь объявить var i - person cobbal; 27.08.2010
comment
@cobbal - OP не объявлял это в вопросе, поэтому я предполагаю, что он объявлен в другом месте или предназначен для глобального использования. Если нет, то да, его можно было бы добавить к другим объявлениям OP. var num = 10, reverse = false, i; - person user113716; 27.08.2010

Попробуйте использовать 2 петли:

if (reverse) {
    for(i=num-1;i>=0;i--){
        console.log(i)
    }
}
else {
    for(i=0;i<num;i++){
        console.log(i)
    }
}
person Ivan Nevostruev    schedule 27.08.2010
comment
Я собирался опубликовать примерно то же самое, что и это. Это кажется мне наиболее естественным и читаемым решением, а также эффективным, флаг обратного направления проверяется только один раз, а не каждый раз в цикле. - person Jay; 27.08.2010

var num = 10,
    reverse = false;

for (var i = 0, n = reverse?num-1:0, d = reverse?-1:1; i < num; i++, n+=d) {
    console.log(n);
}

Это эквивалентно следующему, более удобочитаемому, но менее компактному:

var num = 10,
    reverse = false;

var start = reverse ? num-1 : 0,
    end   = reverse ? -1 : num,
    step  = reverse ? -1 : 1;
for (var i = start; i != end; i += step) {
    console.log(i);
}

Изменить:
На самом деле, эти два решения не идентичны, потому что первое имеет дополнительную операцию приращения. Тем не менее, с точки зрения производительности это ничтожно мало. Если вы действительно хотите получить компактное решение с наилучшей производительностью, вы можете сделать следующее (не для слабонервных):

var num = 10,
    reverse = false;

for (var r=reverse, i=r?num-1:0, n=r?-1:num, d=r?-1:1; i!=n; i+=d) {
    console.log(i);
}

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

person Roy Sharon    schedule 27.08.2010
comment
ржу не могу. Вы написали свой, пока я писал свой (страница обновлялась, когда были опубликованы новые ответы). : P Я злоупотребляю троичными операторами. Рад видеть кого-то, кто пишет как я. - person XstreamINsanity; 27.08.2010
comment
Никакого злоупотребления троичными формами ... Я считаю это злоупотреблением только в том случае, если вы не используете возвращаемое значение тернарного выражения, например, условие? doSomething (): doSomethingElse (); --- Впрочем, совершенно не по делу ... - person Juan Mendes; 27.08.2010
comment
Мне нравится ваше решение, но я нашел еще одно более понятным с точки зрения Патрика. - person Raspo; 28.08.2010

Я просто на днях столкнулся с необходимостью в этом. Вот как я это сделал:

var num = 10,
    i = 0,
    direction = 1, 
    reverse = false;

if(reverse)
    i = num + (direction = num = -1);

for(; i !== num; i += direction) {
    console.log(i);
}

Нет необходимости в отдельных циклах и математике для вычисления правильного i в цикле.

So if reverse is true...

  • i (который представляет наш первый элемент) становится num - 1, поэтому теперь мы начинаем с того, что было бы последним элементом

  • num (который представляет собой выход за пределы) становится -1, поэтому теперь мы останавливаемся на том, что было бы первым элементом

  • direction равно -1, что означает, что он будет уменьшаться, когда мы сделаем i += direction

Таким образом, поменяв местами начальную точку на конечную и изменив изменение i с 1 на -1, мы будем двигаться вверх или вниз в зависимости от этих изменений.

person Community    schedule 03.02.2012

Думаю, это соответствует вашим требованиям:

var num = 10;
var reverse = false;
var diff = 0;

if (reverse) {
    diff = num - 1;
}

for (i = 0; i < num; i++) {
    console.log(Math.abs(diff - i));
}
person Bernard    schedule 27.08.2010

Вот как я всегда делал обратные циклы:

for (i = num; --i >= 0; ) ...
person Mike Dunlavey    schedule 27.08.2010

А в чем проблема:

   if (reverse)
   {
     for(i=num-1; i>=0;i--){ 
          console.log(i);
      }
   }
   else
   {
      for(i=0;i<num;i++){ 
         console.log(i) 
      } 
   }

}

person James Curran    schedule 27.08.2010
comment
Возможно, в производственном коде внутри цикла будет происходить что-то большее, чем простой console.log? - person meagar; 27.08.2010
comment
@meagar: если это так, поместите все внутри цикла в функцию. - person Jay; 27.08.2010

Рой похож на мой, но вот о чем я думал. Я расскажу вам то, что я написал на C #, и то, как я думаю, это переводится на Javascript.

C#

    int num = 10;
    bool reverse = true;

    for (int i = reverse ? num : 0; (reverse ? 0 : i) < (reverse ? i : num); i += reverse ? -1 : 1)
    {
        Console.Write((reverse ? i - 1 : i).ToString());
    }
    Console.ReadKey();

Javascript

        var num = 10,
        reverse = true;

    for (int i = reverse ? num : 0; (reverse ? 0 : i) < (reverse ? i : num); i += reverse ? -1 : 1)
    {
        console.log(reverse ? i - 1 : i);
    }

А вот еще один способ
Javascript

    var num = 10,
        reverse = false;

    for (int i = 0; i < num; i++)
    {
      console.log((reverse ? abs(-num + (i + 1)) : i));

    }
person XstreamINsanity    schedule 27.08.2010
comment
Все они по-прежнему проверяют обратный флаг на каждой итерации цикла. - person Jay; 27.08.2010
comment
ржу не могу. Плохо, я не заметил этой части вопроса. Спасибо, что дал мне знать. Однако, к OP, если вы беспокоитесь о производительности, я бы не стал. Но я подумаю о другом, если смогу. - person XstreamINsanity; 27.08.2010
comment
Я думаю, что OP не знал о тернарных операторах, думая, что в их цикле должен быть if / else. Я все еще думаю о другом пути. - person XstreamINsanity; 27.08.2010

Вроде работает:

  var num = 10;
  var z = 1;
  var k = -10;
  if (reverse ){
    k = -1;
    z = -1;
  }
  for(int i = 0; i < 10; i++){
    console.log(num+i*z+k);
  }
person abele    schedule 27.08.2010

Конечно, в таком языке, как Javascript, должен быть способ определить локальную функцию и использовать ее в цикле?

function SubtractFrom(val, subtractor) {
    return val - subtractor;
}

function PassThrough(val) {
    return val;
}

var num = 10;
var processor = reverse ? SubtractFrom(num-1) : PassThrough;

for (i = 0; i < num; i++) {
    console.log(processor(i));
}

Однако, не зная Javascript, я не знаю, какую фактическую форму могли бы принять определения функций.

person dash-tom-bang    schedule 27.08.2010

person    schedule
comment
i<=end здесь вызовет проблемы, так как проверка должна быть i>=0 в обратном порядке. - person Nick Craver; 27.08.2010
comment
в первом предложении это должно быть end=-1, а во втором предложении end=num. - person Roy Sharon; 27.08.2010