如何在FOR循环中反转顺序

15

我有一个简单的for循环语句,像这样:

var num = 10,
    reverse = false;

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

reverse 为 false 时,我希望它返回类似 [0,1,2,3,4,5,6,7,8,9] 的东西。

但是,当 reverse 为 true 时,它应该返回 [9,8,7,6,5,4,3,2,1,0]。

最有效的方法是什么,而不必在循环内每次都检查 reverse 是 true 还是 false?

我不想这样做:

var num = 10,
    reverse = false;

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

我希望在循环外仅检查一次reverse


1
你实际上想要做什么?因为如果是创建一个数组或在数组上循环,总是可以调用JavaScript函数reverse http://www.w3schools.com/jsref/jsref_reverse.asp - CaffGeek
1
w3schools 不是很好。请查看 w3fools - DwB
12个回答

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

1
不错。我本来想建议使用 for(i = num; i--;) log(i);,但是共识似乎是你的方法最快。 - palswim
对于楼主:请注意,当以相反的顺序打印num时,它将被修改,因此如果您计划在将来使用该值,请确保复制原始值。 - Cristian Sanchez
@Daniel - 非常正确。如果这是一个问题,这里有一个快速替换else语句的方法:else{i=num;while(i--)log(i)}; - user113716
不要忘记在某处声明 var i - cobbal
@cobbal- OP在问题中没有声明它,所以我假设它已经在其他地方声明了,或者是意图成为全局变量。如果不是这样的话,那么它可以被添加到OP的其他声明中。var num = 10, reverse = false, i; - user113716

7
尝试使用两个循环:
if (reverse) {
    for(i=num-1;i>=0;i--){
        console.log(i)
    }
}
else {
    for(i=0;i<num;i++){
        console.log(i)
    }
}

2
我正要发布与此几乎相同的内容。这对我来说似乎是最自然和可读的解决方案,而且也很高效,反转标志只被测试一次,而不是每次通过循环。 - Jay

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

这种方法的优点是只有一个控制结构、每个循环只有一个测试和一个迭代器增加。虽然不如递增/递减迭代器快,但差别微乎其微。


你写完了我才写我的(当新答案发布时,页面刷新了)。 :P 我滥用三元运算符。很高兴看到有人像我一样写作。 - XstreamINsanity
没有使用三元操作符的滥用...我认为只有当您不使用三元表达式的返回值时才会滥用它,例如:condition ? doSomething() : doSomethingElse(); --- 不过这完全与重点无关。 - Ruan Mendes
我喜欢你的解决方案,但我发现Patrick的更清晰。 - Raspo

3
var start; var end; var inc;
if (reverse) {
    start = num-1; end = 0; inc = -1;
}
else {
    start = 0; end = num-1; inc = 1;
}
for(i=start;i!=end;i+=inc){
    console.log(i)
}

5
在这里,i<=end 会引起问题,因为在反向时需要检查 i>=0 - Nick Craver
在第一个子句中应该是 end=-1,而在第二个子句中应该是 end=num - Roy Sharon

2

我最近遇到了这个需求。这是我实现的方法:

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 的数学值。
因此,如果reversetrue ...
  • i(表示第一个项目)变为num-1,因此我们现在从最后一个项目开始

  • num(表示越界)变为-1,因此我们现在停在第一个项目上

  • direction-1,这意味着当我们执行i += direction时它将递减

因此,通过交换起始点和结束点,并将 i 的更改从 1 更改为 -1 ,我们将根据这些修改向上或向下移动。

1

我认为这符合您的要求:

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

1

这是我一直使用的反向循环方法:

for (i = num; --i >= 0; ) ...

0

你对这个有什么问题:

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

}


1
也许在生产代码中,循环内部会发生更多的事情,而不仅仅是简单的“console.log”? - user229044
@meagar:如果是这样,请将循环内的所有内容封装成一个函数。 - Jay

0

Roy的代码和我的类似,不过这是我想的。下面是我用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));

    }

1
所有这些仍然在循环的每次迭代中测试反转标志。 - Jay
哈哈,我的错,我没有看到问题中的那一部分。谢谢你让我知道。然而,对于发帖者,如果您担心性能问题,我不会太担心。但如果有可能,我会想出其他办法。 - XstreamINsanity
我认为原帖的作者不知道三元语句,以为在循环中必须要有if/else。不过我还在考虑其他的方法。 - XstreamINsanity

0

看起来可以工作:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接