Loop guard optimization - javascript

A number of years ago I read a very simple article about loop optimization. In particular, if you have to iterate over a list in Java you can put the guard in the initialization in order to avoid a method call in each iteration:
for (int i = 0; i < list.size(); ++i)
becomes:
for (int i = 0, len = list.size(); i < len; ++i)
Now, I'm working with Javascript where the Array lenght is stored in a variable. So, I was wondering if there is a difference between:
for (var i = 0; i < list.length; ++i)
and:
for (int i = 0, len = list.length; i < len; ++i)
Moreover, I read that prefix increment is preferred since it doesn't evaluate to the value of the expression, right?

Related

Redefining variables for multiple for loops, good or bad practice?

I primarily program in AS3 at work, where the lowest scope is the function and not the executing block. This means the following code works fine
for (var i:int = 0; i < 3; i++) {trace(i);}
but this code results in a warning because apparently i is being redefined.
for (var i:int = 0; i < 3; i++) {trace(i);}
for (var i:int = 0; i < 3; i++) {trace(i);}
That means that I generally have to do something like this to avoid warnings from the compiler (and reprimands from my superiors about "bad practice").
var i:int;
for (i = 0; i < 3; i++) {trace(i);}
for (i = 0; i < 3; i++) {trace(i);}
I've been experimenting in TypeScript lately and I find the let concept for defining executing block scopes very practical. I discussed this with a coworker and he insisted that using let within a loop would be bad practice since the variables get redefined every loop.
Is there a fundamental difference performance-wise between the following two methods in TypeScript?
for (let i:number = 0; i < 3; i++) {console.log(i)}
for (let i:number = 0; i < 3; i++) {console.log(i)}
and
let i:number
for (i = 0; i < 3; i++) {console.log(i)}
for (i = 0; i < 3; i++) {console.log(i)}
When you define a variable with let, the variable is local to the scope.
So when you do this
for (let i:number = 0; i < 3; i++) {console.log(i)}
i is scoped into the loop for.
Is not a bad practice to declare i into each loop.
For exemple if you loop on two different array, you can create two loop to iterate it.
If you use an specific iteraztor name for each you can have code like :
const arrFoo: Array<number> = [0, 1, 2];
const arrBar: Array<number> = [0, 1, 2];
for (let iteratorFoo:number = 0; iteratorFoo < arrFoo.length; i++) {console.log(iteratorFoo);}
for (let iteratorBar:number = 0; iteratorBar < arrBar.length; i++) {console.log(iteratorBar);}
In this case it's a good practice to declare two differents iterator.
Unless you use the same i in each loop.
Like :
let i:number
for (i = 0; i < 3; i++) {console.log(i)} // show 0, 1, 2
for (; i < 6; i++) {console.log(i)} // show 3, 4, 5
And for the performance-wise, the difference is clearly not noticeable to a human.
Edit based on comment :
What about in a case where the loop iterates tens of thousands of times?
for ([initialization]; [condition]; [final-expression])
initialization
An expression (including assignment expressions) or variable declaration evaluated once before the loop begins. Typically used to initialize a counter variable. This expression may optionally declare new variables with var or let keywords. [...]. Variables declared with let are local to the statement.
Reference
So the initialization is evaluated once, even if your loop iterates tens of thousands of times.

Javascript : Omitted Initialize inside Nested For Loop

As we know, we can omit the initialization inside the for loop :
var i = 0;
for(; i < 10; i++) {
// do Something with i
}
However, i figure out if i omit the initialization inside the nested loop as well:
var i = 0;
var j = 0;
for(; i < 10; i++) {
for(; j < 10; j++) {
// only do Something with j
// outner loop only run once
}
}
Solution :
var i = 0;
var j;
for(; i < 10; i++) {
j = 0;
for(; j < 10; j++) {
// everything is fine!
}
}
Can anyone explain whats going on? I'm newbie in Javascript.
The loop runs multiple times, but your 'j' is already ten after the first run of i, so the second loop no longer runs during the next values of i.
If you would write something like this.
for(; i < 10; i++) {
for(; j < 10; j++) {
console.log("test")
}
console.log("another test")
}
You would see that both messages get printed 10 times.
The reason that your "j" loop, only runs "ten times once", is because you do not set J back to zero after it has run 10 times. So the statement j < 10is true for every loop if iafter the first run.
You could solve this by setting j = 0 inside the first for loop (if you do not want to put it inside the variable initialisation of the second loop.)
for(; i < 10; i++) {
j = 0;
for(; j < 10; j++) {
console.log("test")
}
console.log("another test")
}
Every time i increments, you need to reset j to 0.
If you rewrite your script so that each variable is initialised within the for loop statement itself, then every time i increments, j will be reset to 0.
for (var i = 0; i < 10; i++) {
for (var j = 0; j < 10; j++) {
}
}

Objects from same array using for loop with j = i + 1

I have a loop to check collision between objects in my game, all the objects are collected in the same Array. I use a code like this to match every object with eachother:
for (var i = 0; i < objs.length; i++) {
for (var j = i + 1; j < objs.length; j++) {
collision(objs[i], objs[j]);
}
}
Now this does not seem to actually perform all collisions with eachother, I've noticed that it skips some too..
Then I came up with this solution:
for (var i = 0; i < objs.length; i++) {
for (var j = 0; j < objs.length; j++) {
if (j != i) {
collision(objs[i], objs[j]);
}
}
}
This solution seem to not have any problems, but I wonder if there is any kinda way to not have to use the if (j != i) statement, or is there maybe a totally different solution?
Soo, who's correct eh..?
It depends on the definition of collision in your game.
If collision is a symmetric function (i.e. A collides with B if, and only if, B collides with A), then use:
for (var i = 0; i < objs.length; i++) {
for (var j = i + 1; j < objs.length; j++) {
collision(objs[i], objs[j]);
}
}
because there's no need to check (B,A) if you checked (A,B) before.
But if it is possible to make A collide with B without making B collide with A, or vice versa, then you must check all possible different pairs, so use
for (var i = 0; i < objs.length; i++) {
for (var j = 0; j < objs.length; j++) {
if (j != i) {
collision(objs[i], objs[j]);
}
}
}

for loop versus if condition

There are two alternatives I have for executing a piece of code. The code basically resets all the values in three arrays. Two of them are int arrays and one is boolean.
Choice 1
for (i = 0; i < array1.length; i++)
array1[i] = 0;
for (i = 0; i < array2.length; i++)
array2[i] = 0;
for (i = 0; i < array3.length; i++)
array3[i] = false;
Choice 2
int limit = <assign the greatest of the array lengths>
for (i = 0; i < limit; i++)
{
if (i < array1.length)
array1[i] = 0;
if (i < array2.length)
array2[i] = 0;
if (i < array3.length)
array3[i] = false;
}
Which of these would be faster? Given that the arrays can have varying lengths and have no relationship with each other.
There is a real good discussion here. The answer listed first explains quiet well what arrays actually mean in javascript. For those interested to check it out!
This version is almost certainly going to be faster. It is also easier to read and shorter, which are both much more important attributes than speed (99+% of the time).
for (i = 0; i < array1.length; i++)
array1[i] = 0;
for (i = 0; i < array2.length; i++)
array2[i] = 0;
for (i = 0; i < array3.length; i++)
array3[i] = false;
In general, it is faster to access data that is close in memory to data that you accessed recently.
This version also does not suffer from additional branching you would get in the second version.
A sufficiently advanced compiler would transform the second version into the first.
Benchmarking: Micro-benchmarks are 100% useless without profiling your entire program first. Since I don't think the performance measurements are useful, I am not providing them.
function reset_array(array, value) {
var len = array.length;
array.length = 0;
while (len--) array.push(value);
}
reset_array(array1, 0);
reset_array(array2, 0);
reset_array(array3, false);

Why is iterating through an array backwards faster than forwards

Given this code:
var arr = [];
for (var i = 0; i < 10000; ++i)
arr.push(1);
Forwards
for (var i = 0; i < arr.length; ++i) {}
Backwards
for (var i = arr.length - 1; i >= 0; --i) {}
Hard-coded Forward
for (var i = 0; i < 10000; ++i) {}
Why is backwards so much faster?
Here is the test:
http://jsperf.com/array-iteration-direction
Because your forwards-condition has to receive the length property of your array each time, whilst the other condition only has to check for "greater then zero", a very fast task.
When your array length doesn't change during the loop, and you really look at ns-perfomance, you can use
for (var i=0, l=arr.length; i<l; i++)
BTW: Instead of for (var i = arr.length; i > 0; --i) you might use for (var i = arr.length; i-- > 0; ) which really runs through your array from n-1 to 0, not from n to 1.
Because in the first form you are accessing the property length of the array arr once for every iteration, whereas in the second you only do it once.
If you want to have them at same pace, you can do that for forward iteration;
for(var i=0, c=arr.length; i<c; i++){
}
So, your script won't need to take length of array on everystep.
I am not entirely sure about this, but here is my guess:
For the following code:
for (var i = 0; i < arr.length; ++i) {;
}
During runtime, there is an arr.length calculation after each loop pass. This may be a trivial operation when it stands alone, but may have an impact when it comes to multiple/huge arrays. Can you try the following:
var numItems = arr.length;
for(var i=0; i< numItems; ++i)
{
}
In the above code, we compute the array length just once, and operate with that computed number, rather than performing the length computation over and over again.
Again, just putting my thoughts out here. Interesting observation indeed!
i > 0 is faster than i < arr.length and is occurring on each iteration of the loop.
You can mitigate the difference with this:
for (var i = 0, len = arr.length; i < len; ++i) {;
}
This is still not as fast as the backwards item, but faster than your forward option.
do it like below, it will perform in same way. because arr.length takes time in each iteration in forward.
int len = arr.length;
forward
for (var i = 0; i < len; ++i) {
}
backward
for (var i = len; i > 0; --i) {
}
And these are equally good:
var arr= [], L= 10000;
while(L>-1) arr[L]= L--;
OR
var arr= [], i= 0;
while(i<10001) arr[i]=i++;

Categories

Resources