views:

218

answers:

10

I've a simple FOR statement like this:

var num = 10,
    reverse = false;

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

when reverse is false I want it to return something like [0,1,2,3,4,5,6,7,8,9]

but, when reverse is true, it should return [9,8,7,6,5,4,3,2,1,0]

Which is the most efficient way to get this result, without checking every time if reverse is true or false inside the loop?

I don't want to do this:

var num = 10,
    reverse = false;

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

I would like to check reverse only one time outside the loop.

+10  A: 
var num = 10,
reverse = false;

if(!reverse) for(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 ); }

EDIT:

As noted in the comments below, if i is not declared elsewhere and you do not intend for it to be global, then declare it with the other variables you declared.

And if you don't want to modify the value of num, then assign it to i first.

var num = 10,
reverse = false,
i;

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

function log( num ) { console.log( num ); }
patrick dw
Nice. I was going to suggest `for(i = num; i--;) log(i);`, but [the consensus](http://stackoverflow.com/questions/1340589/javascript-are-loops-really-faster-in-reverse) seems to be that your method is fastest.
palswim
To the op: be aware that `num` will be modified when printed in reverse, so be sure to make a copy of the original value if you plan to use that value in the future.
CD Sanchez
@Daniel - Very true. If that's a concern, here's quick replacement for the `else` statement: `else{i=num;while(i--)log(i)};`
patrick dw
don't forget to declare `var i` somewhere
cobbal
@cobbal - The OP didn't declare it in the question, so I assume it is declared elsewhere, or is intended to be global. If not, then yes, it could be added to the OP's other declarations. `var num = 10, reverse = false, i;`
patrick dw
+2  A: 
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)
}
Jerome
The `i<=end` will give issues here, since the check needs to be `i>=0` in reverse.
Nick Craver
should be i!=end
Equiso
Hey that's right. Fixed
Jerome
@Jerome, in the first clause it should be `end=-1`, and in the second clause `end=num`.
Roy Sharon
+2  A: 

Try use 2 loops:

if (reverse) {
    for(i=num-1;i>=0;i--){
        console.log(i)
    }
}
else {
    for(i=0;i<num;i++){
        console.log(i)
    }
}
Ivan Nevostruev
I was about to post pretty much the same thing as this. This seems to me the most natural and readable solution, and is also efficient, the reverse flag is tested only once and not every time through the loop.
Jay
A: 

And what's your problem with:

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

}

James Curran
Perhaps in production code there will be more going on inside the loop than a simple `console.log`?
meagar
@meagar: If so, push everything inside the loop into a function.
Jay
+3  A: 
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);
}

This is equivalent to the following, which is more readable, but less compact:

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

Edit:
Actually, these two solutions are not identical, because the first one has an additional increment operation. Still, it is negligible from performance point of view. If you really want to get a compact solution that has the best performance, you can do the following (not for the faint of heart):

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

This has the advantage of having a single control structure, a single test in each loop, and a single iterator addition. It is not as fast as having an iterator increment/decrement, but only marginally so.

Roy Sharon
lol. You wrote yours as I was writing mine (the page refreshed when new answers were posted). :P I abuse ternary statements. Glad to see someone who writes like me.
XstreamINsanity
@Roy No abuse of ternaries there... I consider it abuse only if you don't use the return value of the ternary expression likecondition ? doSomething() : doSomethingElse(); --- Completely outside the point, though...
Juan Mendes
I like your solution, but I found the patrick's one more clear.
Raspo
+1  A: 

I think this meets your requirements:

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));
}
Bernard
A: 

Roy's is similar to mine, but here's what I was thinking. I'll give you what I wrote in C# and how I think it translates to 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);
    }

And here's another way
Javascript

    var num = 10,
        reverse = false;

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

    }
XstreamINsanity
All of these still test the reverse flag on every iteration of the loop.
Jay
lol. My bad, I didn't see that part in the question. Thanks for letting me know. However, to the OP, if you're worried about performance, I wouldn't. I'll think of something else though, if I can.
XstreamINsanity
I think the OP wasn't aware of ternary statements, thinking they'd have to have an if/else in their loop. I'm still thinking about another way though.
XstreamINsanity
A: 

It seems to work:

  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);
  }
janis.abele
A: 

Surely in a language like Javascript there must be a way to define a local function and use that in the loop?

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

Not knowing Javascript though, I don't know what actual form the function definitions would take.

dash-tom-bang
A: 

Here's how I've always done reverse loops:

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