Iterating Performance Comparison - javascript

I have an array:
deleteIds= ["User1"];
and try to iterate over it as like:
first one:
for (var index = 0; index < len; index++) {
alert(deleteIds[index]);
}
second one:
for (var index in deleteIds) {
alert(deleteIds[index]);
}
What is the performance comparison of them?

This is a micro optimisation at best. Unless you have hundreds of thousands of elements in your deleteIds array, you should not be looking at optimising this.
It turns out that the for(;;;) version is quicker than for in: http://jsperf.com/iterating-over-a-loop/2 (thanks to #Jamiec for the jsperf).
However, what's more important than the performance comparison of these, is that both code snippets are functionally different to each other (live example).
var array = new Array(100);
for (var i = 0; i < array.length; i++) {
console.log(i); // shows 0 - 99
}
for (var x in array) {
console.log(x); // shows nothing
}
Furthermore, if you add methods to either the array, or to an object in the arrays' prototype chain, they will show up in the for (var x in y) loop, but not in for (;;;); (live example):
Array.prototype.foo = function() {};
var array = [];
for (var i = 0; i < array.length; i++) {
console.log(i); // nothing
}
for (var x in array) {
console.log(x); // `foo`
}
You can use hasOwnProperty to eliminate the attributes inherited from the prototype chain, but that won't stop you receiving methods directly on the object (live example):
Array.prototype.foo = function() {};
var array = [];
array.bar = function () {};
for (var i = 0; i < array.length; i++) {
console.log(i); // nothing
}
for (var x in array) {
if (array.hasOwnProperty(x)) {
console.log(x); // `bar`
}
}
It is because of these reasons that using for in for iterating over an array is discouraged, and the for(;;;) version should always be used instead. for in should be used for iterating over an object.

Related

Huge performance difference between methods of calculating a hash. This can't be right, right? [duplicate]

I wanted to extend String object prototype with some utility method. It worked, but the performance was surprisingly low. Passing a string to a function is 10x times faster than overriding the String.prototype method that is doing the same thing. To make sure this really happens I created a very simple count() function and the corresponding methods.
(I was experimenting, and created three different versions of the method.)
function count(str, char) {
var n = 0;
for (var i = 0; i < str.length; i++) if (str[i] == char) n++;
return n;
}
String.prototype.count = function (char) {
var n = 0;
for (var i = 0; i < this.length; i++) if (this[i] == char) n++;
return n;
}
String.prototype.count_reuse = function (char) {
return count(this, char)
}
String.prototype.count_var = function (char) {
var str = this;
var n = 0;
for (var i = 0; i < str.length; i++) if (str[i] == char) n++;
return n;
}
// Here is how I measued speed, using Node.js 6.1.0
var STR ='0110101110010110100111010011101010101111110001010110010101011101101010101010111111000';
var REP = 1e3//6;
console.time('func')
for (var i = 0; i < REP; i++) count(STR,'1')
console.timeEnd('func')
console.time('proto')
for (var i = 0; i < REP; i++) STR.count('1')
console.timeEnd('proto')
console.time('proto-reuse')
for (var i = 0; i < REP; i++) STR.count_reuse('1')
console.timeEnd('proto-reuse')
console.time('proto-var')
for (var i = 0; i < REP; i++) STR.count_var('1')
console.timeEnd('proto-var')
Results:
func: 705 ms
proto: 10011 ms
proto-reuse: 10366 ms
proto-var: 9703 ms
As you can see the difference is dramatic.
The below proves that performance of method calls is neglectably slower, and that the function code it self is slower for methods.
function count_dummy(str, char) {
return 1234;
}
String.prototype.count_dummy = function (char) {
return 1234; // Just to prove that accessing the method is not the bottle-neck.
}
console.time('func-dummy')
for (var i = 0; i < REP; i++) count_dummy(STR,'1')
console.timeEnd('func-dummy')
console.time('proto-dummy')
for (var i = 0; i < REP; i++) STR.count_dummy('1')
console.timeEnd('proto-dummy')
console.time('func-dummy')
for (var i = 0; i < REP; i++) count_dummy(STR,'1')
console.timeEnd('func-dummy')
Results:
func-dummy: 0.165ms
proto-dummy: 0.247ms
Although on huge repetitions (like 1e8) prototyped methods proves to be 10x times slower than functions, this can be ignored for this case.
All this may be related only to a String object, because simple generic objects perform about the same when you pass them to functions or call their methods:
var A = { count: 1234 };
function getCount(obj) { return obj.count }
A.getCount = function() { return this.count }
console.time('func')
for (var i = 0; i < 1e9; i++) getCount(A)
console.timeEnd('func')
console.time('method')
for (var i = 0; i < 1e9; i++) A.getCount()
console.timeEnd('method')
Results:
func: 1689.942ms
method: 1674.639ms
I've been searching on Stackoverflow and binging, but other that the recommendation "do not extend String or Array because you pollute the name space" (which is not a problem for my particular project), I cannot find anything related to performance of methods compared to functions. So should I simply forget about extending the String object due to performance drop of added methods or there is more about it?
This is most likely because you are not using strict mode, and the this value inside your method is getting coerced to a String instance instead of being a primitive string. This coercion, and further method calls or property accesses on the String object, are slower than using primitive values.
You can (Edit: could, at least, in 2016) confirm this by repeating your measurement on var STR = new String('01101011…') which should have less overhead.
Then fix your implementation:
String.prototype.count = function (char) {
"use strict";
// ^^^^^^^^^^^^
var n = 0;
for (var i = 0; i < this.length; i++)
if (this[i] == char)
n++;
return n;
};

Speed of looping through an array vs. looping through an object

I'm not sure if this has been asked already, if it has, let me know in the comments and I'll delete the question. What's faster, looping through an object or looping through an array? For instance, if I have two arrays that are the exact same length(required for the script to run properly, not gonna get into details), each position in one array is associated with a position in the other array. So it looks like this:
var array_variable = ["get_ped_bridges", "get_rail_bridges"];
var array_url = ["http://eg.com/rest/services/Nope/MapServer/1", "http://eg.com/rest/services/Nope/MapServer/2"];
for(var j = 0; j < array_variable.length; j++){
console.log(array_variable[j], array_url[j]);
}
So as you can see, each url matches up to a position in the array_variable array. In an object, it would look something like this:
var object = {
one: {
variable: "get_ped_bridges",
url: "http://eg.com/rest/services/Nope/MapServer/1"
},
two: {
variable: "get_rail_bridges",
url: "http://eg.com/rest/services/Nope/MapServer/2"
}
}
So, if the lengths of both were substantially longer(the actual length would probably be around 20 positions), which loop would process faster?
The short answer is that generally an array is faster.
This is because of continuos indexing in an array, where it is always exactly known where the next element is (because it's stored contiguously)
you can refer to this previous answer for more info: Array vs. Object efficiency in JavaScript
<script src="http://broofa.com/Tools/JSLitmus/JSLitmus.js"></script>
<script>
JSLitmus.test('Array', function() {
var array_variable = ["get_ped_bridges", "get_rail_bridges"];
var array_url = ["http://eg.com/rest/services/Nope/MapServer/1", "http://eg.com/rest/services/Nope/MapServer/2"];
for (var j = 0, len = array_variable.length; j < len; j++) {
//
}
for (var j = 0, len = array_url.length; j < len; j++) {
//
}
});
JSLitmus.test('Object', function() {
var object = {
one: {
variable: "get_ped_bridges",
url: "http://eg.com/rest/services/Nope/MapServer/1"
},
two: {
variable: "get_rail_bridges",
url: "http://eg.com/rest/services/Nope/MapServer/2"
}
};
for (var i in object) {
//
}
});
</script>

Most performant way to build object from array of objects

Currently, I'm building an object from an array of objects with the following:
var popOverOptions = {
defaultOption: true
}
if (a) {
options.push({a: "b"});
}
if (c) {
options.push({c: "d"});
}
// Loop through array of objects
for (var i = 0; i < options.length; i++) {
// Add objects in array to popoverOptions object
for (key in options[i]) {
popoverOptions[key] = options[i][key]
}
}
I'm thinking this could be optimized and I'm curious if there is a better way to write this, possibly using .reduce(), .forEach() or some other method.
In ECMAScript 6, you can use
Object.assign to copy the properties to popOverOptions
The spread operator to expand the options array.
Object.assign(popOverOptions, ...options);
You can optimise the loop itself like this:
for (var i=0, n=options.length; i<n; ++i) {
This reduces the number of times you need to access options.length which is slower than reading it from a local.
A smaller optimisation:
for (var i=options.length-1; i--; /* empty */) {
Source: http://www.phpied.com/extreme-javascript-optimization/
You can cache length for a slight speed improvement.
If the keys in your array are identical for each element, you can get twice the speed (in Chrome) by caching Object.keys(options[0]), and iterating through that.
Even if the keys aren't the same, you can still get approx. 25% increase in speed by iterating through Object.keys(options[i]).
var options= [];
for(var i = 0 ; i <= 1000 ; i++) { //create array of objects with random numbers
options[i]= {};
for(var j = 0 ; j <= 5000 ; j++) {
options[i][j]= Math.random();
}
}
var popOverOptions = {};
function keyin() {
var timer= new Date();
for(var i = 0, leni = options.length ; i < leni; i++) {
for(var key in options[i]) {
popOverOptions[key] = options[i][key];
}
}
alert((new Date()-timer)/1000+' seconds');
} //keyin
function objkeys(same) {
var timer= new Date(),
keys= Object.keys(options[0]);
for(var i = 0, leni = options.length ; i < leni; i++) {
if(!same) keys= Object.keys(options[i]);
for(var key = 0, lenk = keys.length ; key < lenk ; key++) {
popOverOptions[keys[key]] = options[i][keys[key]];
}
}
alert((new Date()-timer)/1000+' seconds');
} //objkeys
<button onclick="keyin()">key in options</button><br>
<button onclick="objkeys(true)">Object.keys, same keys per element</button><br>
<button onclick="objkeys(false)">Object.keys, different keys per element</button>

javascript: Prevent representing added Array's attributes as elements (in Chrome)

I am using this snippet to extend Array's functionality with getUnique function:
Array.prototype.getUnique = function() {
var u = {}, a = [];
for (var i = 0, l = this.length; i < l; ++i) {
if (u.hasOwnProperty(this[i])) {
continue;
}
a.push(this[i]);
u[this[i]] = 1;
}
return a;
};
The slight drawback is that the attribute getUnique is printed together with array elements if I console.log an array:
["126", "125", getUnique: function]
It is slightly disturbing even if I know that getUnique is not considered as an array element. This happens in Chrome. Not in Firefox as far as I know. Is there a way to prevent it?
Use Object.defineProperty and enumerable:
Object.defineProperty(Array.prototype, 'getUnique',
{ enumerable: false
, configurable: true
, writable: true
, value: function ()
{ var u = {};
var a = [];
for (var i = 0, l = this.length; i < l; ++i)
{ if (u.hasOwnProperty(this[i])) continue;
a.push(this[i]);
u[this[i]] = 1;
}
return a;
}
});
By default, a property is enumerable (even if it's not a direct property of an instance), which means that it is visible through any for-in loop (or Object.keys) of the array. Chrome does something similar to a for-in loop on an array, which is why it is represented as it is.
Note that this function only works in (relatively) modernish browsers which support ES5, which means that IE < 9, some older Android browsers and other mobile devices may not be able to use this code. This is one of the reasons why some people recommend against extending the prototypes of native constructors, as this issue can break code that isn't well constructed against these issues. What people who believe this usually recommend is to not place the function on the prototype:
function getUnique(arr)
{ var u = {};
var a = [];
for (var i = 0, l = array.length; i < l; ++i)
{ if (u.hasOwnProperty(arr[i])) continue;
a.push(arr[i]);
u[arr[i]] = 1;
}
return a;
}
I'd also like to point out that only one object will be ever printed by the getUnique function, as it is technically incorrect in its implementation. While rather similar, objects are not dictionaries and can only have string keys, which means that any object (no matter the contents) will have a string value of '[object Object]', which means that when your function encounters another object (even if it has different values), it will not be added to the returned array. While inefficient, the only way I can think of is to iterate through the array each time:
function getUnique(arg)
{ 'use strict';
var O = Object(arg);
var len = O.length >>> 0;
var A = [];
var indexOf = function (arg, searchElement)
{ for (var i = 0, l = arg.length; i < l; ++i) if (arg[i] === searchElement) return i;
return -1;
};
for (var k = 0; k < len; ++k)
{ var elementK = O[k];
var kPresent = k in O;
if (!kPresent || indexOf(A, elementK) !== -1) continue;
A[A.length - 1] = elementK;
}
return array;
}

How can I iterate over all unique pairs of entries in an object?

I currently have an array data structure that I iterate over like this, calling foo on each unique pair of elements.
for(var i = 0; i < arr.length; i++) {
for(var j = i + 1; j < arr.length; j++) {
foo(arr[i], arr[j]);
}
}
However, I've realized that I'd rather use an object instead of an array, since I can then add and remove elements by name very easily.
However, I can't see an obvious way to iterate over such an object. The closest I can get is:
for(i in obj) {
for(j in obj) {
foo(obj[i], obj[j]);
}
}
Obviously, this will do each pair twice, and even produce a pair of identical elements. Is there an easy way to iterate over an object in the same way as I do in the array in my first code sample?
Update:
Performance testing the solutions on jsperf.
My solution that was at first written as a comment:
Add an if (i < j) condition in the inner loop. It might not be the best solution, but it would work as long as the foo function does the same thing for foo(2, 10) and foo(10, 2):
for(i in obj) {
for(j in obj) {
if (i < j) {
foo(obj[i], obj[j]);
}
}
}
Assuming I understand your question... maybe check to see if the value has already been visited by the outer loop?
var visited = {}
for(i in obj) {
visited[i] = true;
for(j in obj) {
if(j in visited){ continue; }
foo(obj[i], obj[j]);
}
}
Use Object.keys() to get the list of keys out as an array:
keys = Object.keys();
for(i=0;i<keys.length;i++) {
for(j=i+1;j<keys.length;j++) {
foo(obj[keys[i]], obj[keys[j]]);
}
}
Maybe You can try unset used objects:
for(i in obj) {
var a = obj[i];
delete obj[i];
for(j in obj) {
foo(a, obj[j]);
}
}
http://jsfiddle.net/bXcvb/
If you need to original obj in tact see: How do I correctly clone a JavaScript object?
You can push the object keys into an array:
var obj_keys = [];
for (i in obj) {
obj_keys.push(i);
}
for(i = 0; i < obj_keys.length; ++i) {
for(j = i + 1; j < obj_keys.length; ++j) {
foo(obj[obj_keys[i]], obj[obj_keys[j]]);
}
}

Categories

Resources