I have two numbers in javascript.
They are integral coordinates.
I also have an object: var regions = {};
I'd like to be able to access specific objects as quickly as possible.
E.g. there could be an object at (5,-2)
What's a fast way of creating unique hashes, that do not clash, for two numbers like this?
I'm assuming the "specific objects" you want to access are referenced by properties on regions. Object properties in JavaScript are named either by string names or by Symbol names. You'd be using strings in this case.
Since it's going to be by string, the simple solution is just create a string, and look it up with that:
var obj = regions[num1 + "," + num2];
That leaves it up to the JavaScript engine to do a good job looking up the property. JavaScript engines are very good (read: fast) at this, because they have to do it a lot.
How the engine does the lookup will depend in some measure on how the regions object is created. Wherever possible, modern engines will create objects that are effectively micro-classes and provide very quick resolution of property names. If you do certain things (like using delete on one of the properties), a modern engine may fall back to "dictionary" mode where it uses a hash lookup. This is still fast, just not as fast as the optimized form.
I doubt you'll find a quicker way that that. In theory, if region were a contiguous array where elements referenced contiguous arrays, the JavaScript engine could make those true arrays under the covers, and one of your example numbers is negative which would prevent a true array from being used. And you'd still be doing two lookups (the first number, then the second), and there's no guarantee it would be faster. It would certainly be more complicated.
As you've said you'll receive the information in dribs and drabs, I'd go with a simple compound string key until/unless you have a performance problem with that solution, then look at trying to get contiguous arrays happening on your target engines (converting those negative indexes into something else, which could be problematic). I doubt you'll find that the lookup is every the bottleneck.
You can use array notation:
var regions = {}
regions[[5,-2]] = myObject;
regions[[5,-2]]; // myObject
Object keys can't be arrays, so under the hood [5,-2] will be stringified to "5,-2". But I think that using array notation is more pretty than stringifying manually.
Example:
var regions = {
'5,-2': { ... },
'1,3': { ... }
};
and then if you have the 2 numbers you could easily generate the key and access the corresponding object:
var x = 5;
var y = -2;
var obj = regions[x + ',' + y];
I used two function encode and decode.
var x = 10;
var y = -3.2;
function encode(x, y) {
return x + ',' + y;
}
function decode(code) {
var xy = code.split(',');
return [+xy[0], +xy[1]];
}
var code = encode(x, y);
console.log(code);
var xy = decode(code);
console.log(xy);
The code can be used as dict key value.
Related
Let's say you want to compare two javascript objects or arrays for reference equality.
The most obvious solution would be
if (a === b) { /*...*/ };
The problem with this is that a and b would have to hold the references to actual objects. This can be a problem in same cases. For example, trying to hold actual references in a memoization function would create a memory leak.
One approach is to use JSON.stringify(a) to obtain string representations of objects and compare that. But that can be prohibitively expensive in some use cases. Not to mention that actual reference equality isn't taken into consideration.
That got me wondering. Is there a way to stringify an actual reference instead of the object contents? Obviously, you can't manipulate pointers in javascript, but what if you could get just a pointer representation of some kind. A hash sum? Raw memory location? Guid or integer representation?
I know there are some kinds of object id-s when analyzing memory dump in chrome dev tools. Maybe these things can be accessed during runtime? Using some kind of special switch in node.js?
Can anyone think of a way to get this done in javascript?
If you want to use this for memorization (caching), you should use the ES6 WeakMap. It works from Firefox 6, Chrome 36 and IE 11 on.
The WeakMap object is a collection of key/value pairs in which the keys are objects and the values can be arbitrary values.
[...]
The experienced JavaScript programmer will notice that this API could be implemented in JavaScript with two arrays (one for keys, one for values) shared by the four API methods. Such an implementation would have two main inconveniences. The first one is an O(n) search (n being the number of keys in the map). The second one is a memory leak issue.
It works like a map in Java - you can use arbitrary objects as keys and as values. But the keys won't prevent garbage collection, so you don't have to worry about memory leaks, but still can find the memorized calculation for a given object.
Inspired by #user2864740's remark (dude, set up a name, seriously :-)).
it could also be simply a required method on the objects that will participate in this system
This implementation extends Object prototype to include a utility to generate unique UUID for each object. generateId implementation is taken from here.
Seems to be working for objects and arrays.
Object.prototype._id = function () {
return this.__id || (this.__id = generateId());
function generateId() {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
}
}
function assert(message, test) {
if (!test) {
throw new Error("ASSERTION FAILED: " + message);
} else {
console.log("PASSED: " + message);
}
}
var x = { name: "same" },
y = { name: "same" },
z = [],
x2 = x;
assert("Id is unchanging", x._id() === x._id());
assert("Id is different for different objects", x._id() !== y._id());
assert("Arrays have id too", z._id() === z._id());
assert("Id is same for same objects", x._id() === x2._id());
Live example
I'm leaving this here to see if there are problems or if maybe someone has a better idea.
Before fully defining my question, I must say that >>this question/answer<< doesn't answer my problem, and I have proven it to myself that the given answer doesn't match at all with the actual effect of property vs. variable or cached property (see below).
I have been using HTML5 canvas, and I write raw pixel blocks many times in a second in a 640x480 area.
As advised by some tutorials, it is good to cache the .data property of an ImageData variable (in this case, it would be _SCimgData).
If I cache that property in SC_IMG_DATA, I can putImageData repeatedly in the Canvas with no problem; but if I repeatedly access it directly with _ScimgData.data, the slow-down of the code is noticieable (taking nearly 1 second to fill a single 640x480 Canvas):
var SomeCanvas = document.getElementById("SomeCanvas");
var SCContext = SomeCanvas.getContext("2d");
var _SCimgData = SomeCanvas.getImageData(0, 0, 640, 400);
var SC_IMG_DATA = _SCimgData.data;
Now I have the following doubt:
Would my code be as slow for other kinds of similar accesses?
I need an array of objects for a set of functions that can have several "instances" of an object (created by a regular utility function), and that need the index of the instance in an array of objects, either to create/initialize it, or to update its properties.
My concrete example is this:
var objArray=new Array();
var objArray[0]=new Object();
objArray[0].property1="some string property";
for(var x=0; x<65536; x++)
doSomething(objArray[0].property1, objIDX=0);
Would that code become as unacceptably slow as in the Canvas case, if the properties and functions contained in some properties are called very intensively (several times in a single milisecond, of course using setInterval and several "timer threads" to avoid locking the browser)?
If so, what other alternative is there to speed up access for the different properties of several objects in the main object array?
EDIT 1 (2012-08-27)
Thanks for the suggestions. I have up-voted them since I suspect they will be useful for the project I'm working on.
I am thinking in a combination of methods, using mainly Arrays instead of Objects to build an actual array of "base objects", and addressing array elements by numbers (arr[0]) instead of string array keys (arr["zero"]).
var OBJECTS_SIZE=10
var Obj_Instances=new Array();
Obj_Instances[0]="property or array 1 of Object 0";
Obj_Instances[1]=new Array();
Obj_Instances[1][0]=new ArrayBuffer(128);
Obj_Instances[1][1]=new DataView(Obj_Instances[1][0]);
Obj_Instances[2]="property or array 3 of Object 0";
Obj_Instances[3]=function(){alert("some function here")};
Obj_Instances[4]="property or array 5 of Object 0";
Obj_Instances[5]="property or array 6 of Object 0";
Obj_Instances[6]=3;
Obj_Instances[7]="property or array 8 of Object 0";
Obj_Instances[8]="property or array 9 of Object 0";
Obj_Instances[9]="property or array 10 of Object 0";
Obj_Instances[10]="property or array 1 of Object 1";
Obj_Instances[11]=new Array();
Obj_Instances[11][0]=new ArrayBuffer(128);
Obj_Instances[11][1]=new DataView(Obj_Instances[11][0]);
Obj_Instances[12]="property or array 3 of Object 1";
Obj_Instances[13]=function(){alert("some function there")};
Obj_Instances[14]="property or array 5 of Object 1";
Obj_Instances[15]="property or array 6 of Object 1";
Obj_Instances[16]=3;
Obj_Instances[17]="property or array 8 of Object 1";
Obj_Instances[18]="property or array 9 of Object 1";
Obj_Instances[19]="property or array 10 of Object 1";
function do_Something_To_Property_Number_6(objIdx)
{
//Fix the index to locate the base address
//of the object instance:
///
objIdx=(objIdx*OBJECTS_SIZE);
Obj_instances[objIdx+6]++; //Point to "Property" 6 of that object
}
I would have, say an "instance" of an "object" that takes up the first 10 array elements; the next "instance" would take the next 10 array elements, and so on (creating the initialization in a custom "constructor" function to add the new block of array elements).
I will also try to use jsPerf and JSHint to see which combination result better.
To answer your "doubts", I suggest using JSPerf to benchmark your code. One can't really tell by code alone if the procedure is faster than another unless tested.
Also, I suggest you use the literal notation for arrays and objects instead of the new notation during construction:
var objArray=[
{
property : 'some string property'
}, {
...
},
];
Also, based on your code, it's better to have this since you are using the same object per iteration:
var obj = objArray[0].property1,
objIDX = 0;
for(var x=0; x<65536; x++){
doSomething(obj,objIDX);
}
I realise this is not quite answering your question (as it has already been answered), however as you seem to be looking for speed improvements in regard to function calls that happen thousands of times (as others who find this might also be doing). I thought I'd include this here as it goes against assumptions:
An example function:
var go = function (a,b,c,d,e,f,g,h) {
return a+b+c+d+e+f+g+h;
}
The following is how you would normally call a repetitive function:
var i=500000; while(i--){
go(1,2,3,4,5,6,7,8);
}
However, if none (or a few) of those arguments ever change for this particular usage of the function, then it's far better to do this (from a speed pov - obviously not an asynchronous pov):
var i=500000; go.args = [1,2,3,4,5,6,7,8];
while(i--){
go();
}
In order for the above to work you only need a slight modification to the original function:
var go = function (a,b,c,d,e,f,g,h, i) {
if ( go.args ) {
i = go.args;
a = i[0]; b = i[1];
c = i[2]; d = i[3];
e = i[4]; f = i[5];
g = i[6]; h = i[7];
}
return a+b+c+d+e+f+g+h;
}
This second function runs significantly faster because you are not passing in any arguments (a function called with no args is very quick to initiate). Pulling the values from the .args array doesn't seem to be that costly either (unless you involve strings). Even if you update one or two of the args it's still far faster, which makes it perfect for pixel or imagedata manipulations because you are normally only shifting x & y:
var i=500000; go.args = [1,2,3,4,5,6,7,8];
while(i--){
go.args[2] = i;
go();
}
So in a way this is an example of where an object property can be faster than local vars - if a little convoluted and off topic ;)
Possible browser optimizations notwithstanding, accessing a property of an object is more expensive than accessing a local variable (but not necessarily a global variable or a variable of a parent function).
The deeper the property, the more of a performance hit you take. In other words,
for(var x=0; x<65536; x++)
doSomething(objArray[0].property1, objIDX=0);
would be improved by caching objArray[0].property1, and not repeatedly assigning to objIDX:
var prop = objArray[0].property1;
objIDX = 0;
for(var x=0; x<65536; x++)
doSomething(prop, 0);
In PHP, if you do this
$var = array();
$var[5000] = 1;
echo count($var);
It prints 1.
In JS it makes the "missing" elements.
<script type="text/javascript">
var fred = [];
fred[10] = 1;
alert(fred.length);
</script>
Alerts "11".
Can I prevent this? Is it good for anything? I'm a PHP coder trying to adapt to Javascript.
EDIT:
I'm working on an app that uses Google Maps v2 and markerManager. The code has been working for ages, but a problem has suddenly arisen in Chrome (17.0.963.56 m) where markers seem to be duplicated (or more) and then rendering moved markers goes completely wrong, often followed by a browser freeze-up. Looking in the DOM using Firebug, I found gazillions of "undefined" elements in arrays under the grid_ variable in markerManager. I figured that, if I could remove these, I might have slicker code, whether it fixes the marker problem or not. Thanks.
As a PHP coder, you're accustomed to array keys being fairly arbitrary. In JavaScript however, if you assign an array element numerically that doesn't exist, the array will be allocated with empty elements up to the one you created. That's the behavior you found. Objects, on the other hand, denoted by {} rather than [], accept arbitrary property names (with caution) and function a little more closely to how you're accustomed PHP's array structures functioning. This is not to say that JavaScript objects (or object literals) are a direct analogue to PHP arrays....
If what you want is a data structure with a key called "10", that is a job for an object literal (though it isn't great practice to name object properties numerically.
var fred = {};
fred["10"] = 1;
Note, the more normal syntax of dealing with an object literal is the object.property notation, but that is not valid for numeric properties:
// name as a property
fred.name = "fred";
// Syntax error...
fred.10 = 10;
// Use [] notation for numeric properties:
fred["10"] = 10;
Object literals do not have a length property, however. So you cannot do:
fred.length;
// undefined
You may use an object instead of an array, but you loose some of the benefits of an array, like access to a length property.
<script type="text/javascript">
var fred = {};
fred['10'] = 1;
// alert(fred.length); // won't work anymore
</script>
On the other hand no extra entries will be generated and the access to a specific value works almost the same way as in an array. If you want to traverse all values, use the following:
for( var el in fred ) {
if ( fred.hasOwnProperty( el ) ) {
alert( fred[ el ] );
}
}
I've been reading, and they're saying that associative arrays won't give you the same efficiency as arrays. An associative array can look things up in O(N) time, where an array can look things up in O(1).
Here's my question: which one would be more efficient in terms of looking up values quickly and not hogging too much memory?
Associative:
var myVars=new Array();
myVars['test1'] = a;
myVars['test2'] = b;
myVars['test3'] = c;
... (up to 200+ values)
echo myVars['test2'];
Stored Associative:
var myVars=new Array();
var TEST1 = 1;
var TEST2 = 2;
var TEST3 = 3;
... (up to 200+ values)
myVars[TEST1] = a;
myVars[TEST2] = b;
myVars[TEST3] = c;
... (up to 200+ values)
echo myVars[TEST2];
First, the first usage of Array is wrong. Although it is possible to do it, it does not mean you should. You are "abusing" the fact that arrays are objects too. This can lead to unexpected behaviour, e.g. although you add 200 values, myVars.length will be 0.
Don't use a JavaScript array as associative array. Use plain objects for that:
var myVars = {};
myVars['test1'] = a;
myVars['test2'] = b;
myVars['test3'] = c;
Second, in JavaScript there is no real difference between the two (objects and arrays). Arrays extend objects and add some behaviour, but they are still objects. The elements are stored as properties of the array.
You can find more information in the specification:
Array objects give special treatment to a certain class of property names. A property name P (in the form of a String value) is an array index if and only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal to 232−1. (...)
So both:
var obj = {'answer': 42};
obj['answer'];
and
var arr = [42];
arr[0];
have the same access time†, which is definitely not O(n).
†: It is better to say should have. Apparently this varies in different implementations.
Apart from that, your second example is horrible to maintain. If you assign numbers to variables, why not use the numbers directly?
var myVars = [];
myVars[0] = a;
myVars[1] = b;
myVars[2] = c;
Update:
More importantly: You have to choose the right data structure for your needs and this is not only determined by the access time of a single element, but also:
Are the keys consecutive numbers or arbitrary strings/numbers?
Do you have to access all (i.e. loop over all) elements of the collection?
Numerical arrays (arrays) and associative arrays (or hash tables/maps (objects in JS)) provide different solutions for different problems.
I posit that the present responses do not fully consider more practical use cases. I created this jsperf to demonstrate. While #Felix's jsperf demonstrates lookup speed, it's not performed on sufficiently large objects to be really useful. I think 10,000 simple properties is more reasonable. Further, you need to randomly select keys in the sequence to read, modify, delete and create to truly demonstrate the performance differences between the two types.
First of all, whoever they are, feel free to ignore them.
Every decent implementation of every decent scripting language, including JavaScript, will give you associative arrays that are either O(log(n)) access time, or else O(1) average access time, O(n) worst case (which you almost never hit). Either way in practice a lookup is fast.
Arrays have O(1) guaranteed access time, which is incredibly fast. But in some scripting languages (eg PHP) there isn't even a native array type provided. They just use associative arrays for both.
Answer: test it out yourself.
Update: After some back-and-forth with Felix, it appears that array access is usually faster than both associative arrays and objects. This is not always the case, notably in Chrome. In Chrome 11 on Ubuntu 11, arrays are faster. In Chrome 11 on Mac OS 10.6 there is no notable difference between them.
These tests did not measure manipulation, only reading.
If I have a Javascript list which will have only numeric keys, which takes less memory?
var array = [];
array[0] = 'hello';
array[5] = 'world';
array[50] = 'foobar';
var obj = {};
obj[0] = 'hello';
obj[5] = 'world';
obj[50] = 'foobar';
I don't know a ton about Javascript engine internals, so...
The reason I ask is because that array, when converted to a string, will have a bunch of undefined's in the middle of it. Are those actually stored in some fashion, or is that just put in at string conversion?
An array is basically an ordered set of values associated with a single variable name.
In your example I think you try to do an associative array, and you should use object, Array is not meant to be used for key/value pairs.
Also the array length is indirecly increased when you assign a value to an index with higher length of the current array length:
var array = new Array();
array[99] = "Test";
// array.length is now 100
Check this detailed article on the subject.
Probably the Javascript array because you can 'only' use numeric key values, where as the object literals provide a space for key values, and even if you use numerical key values, they are probably handled differently than the numerical key values for arrays.
Most likely the reason arrays can't have text-based key values are because they are treated differently than object literals. I'm guessing that because they are probably treated differently, the processing for the array probably is more optimized for numeric key values, were as a object literal is optimized to use strings or numbers as their keys.
JavaScript doesn't implement arrays like other languages so you don't get any performance enhancements inherent of a normal array (memory-wise); in JavaScript an array is very similar to an object; actually, it is essentially an object just with a few extra methods and capabilities (such as a length that updates itself). I'd say neither is quicker.