Array length Vs Number of values in Array - javascript

Recently i had to make an Array with values at large indexes (due to plugin constraints).
eg:
var names[100000] = "a";
var names[150000] = "b" ... and so on till 5 large indexes.
and in between all values are undefined names[100001] //undefined.
Now my doubt is Since the array has only 5 elements but if i do
names.length //it is 300001
its a large Array. I am not iterating this array nor i am running any loop through it. I will get the values directly through their defined indexes from the array.
So will this structure make any significant performance differences on the Browser or is it alright to use this as long as the number of values in the array is less irrespective of its indexes and no iteration is involved.
Thanks

The only thing that differentiates an array from a plain object is its length property and how it behaves (and a few array specific methods of course). The length value simply increases with certain operations, like setting a numeric property or pushing a new element. That's it in a nutshell. The array doesn't actually contain 100000 elements when you set the property 100000 to a value, all that's happening is that you're setting one property and the value of length is adjusted accordingly.
So, no, it won't have a lot of impact on performance, unless somebody actually iterates through the array using for (let i = 0; i < arr.length; i++).

You can create an array with the length, given by your plugin and work locally with an object to limit the iterations. After all your processing has been applied, you copy the values to the array and send it to the plugin's function.
Keep an array with the desired length as a buffer
var buffer = new Array(20000);
Internally work with an object
var data = {};
Assign values to the object
data[10001] = "foo";
Once transformations or data processing has been applied to the object, copy data to the buffer
for (key in data){
buffer[key] = data[key];
}
Send buffer to the plugin. And clear data, if desired.
By doing so, you will not iterate more, than the actual data you processed.

Related

how is this function mutating non-returned array

I'd ask a better question, but I don't don't know how. Thanks for your help.
***ISSUE: I'm sending array vari to a function and it's coming back changed even though I didn't return it or even use same variable name. Desired function: variable vari does not change
I've logged the function and isolated the change to the [].forEach() statement below, noted with ***. I send vari but return varis and assign to new variable sum. How does this change the vari variable?
//this is what calls the sub function using vari, an array, 411.0, 13.0
var sum = doSum1(vari);
function doSum1(vari0) {
// called from doSum1
// grab Variance data // ALL COLUMNS FOR NOW // fix loc/stat columns below
var vstat = vari0[0].indexOf('Status');
vari1 = vari0.filter(r=>r[vstat]); // to ensure indexOf works, and speed processing
var vhdr = ['Campaign ID','Campaign','Site ID','Site','Placement','Placement ID','Date','DCM Imp','Upw Imp','Tag Location','Status','Site Count','Site Imp'];
// move loc and status over in place of variance and percent (loc/stat will be site ct/imp)
varis=[];
// *** THIS FOREACH CHANGES varis AND vari. Not sure how... see more specifically below
['Not Tracking','Undertracking','Overtracking','Absent in DCM'].forEach(rf=>{
varis.push(vhdr.map(r=>''));
varis[varis.length-1][0]=rf;
varis.push(vhdr);
if(vari1.filter(r=>r[vstat].indexOf(rf)>=0).length==0) {
varis.push(vhdr.map(r=>''));
varis[varis.length-1][0]='none found';
} else {
varis.push(vari1.filter(r=>r[vstat].toString().indexOf(rf)>=0)[0]); // break out of outer []
//fix loc/stat location
//*** MORE SPECIFICALLY, this line in particular changes in vari, not just varis as intended.
varis[varis.length-1].splice(9,4,varis[varis.length-1][11],varis[varis.length-1][12],'','')
}
varis.push(vhdr.map(r=>'')); // trailing blank line
});
return varis;
I tried this in place of the splice as well, but same result... just not sure how varis is changing vari...
varis[varis.length-1][9] = varis[varis.length-1][11];
varis[varis.length-1][10] = varis[varis.length-1][12];
varis[varis.length-1][11] = '';
varis[varis.length-1][12] = '';
vari is a 2D array. That means that every element in vari is an array as well, and as such passed by reference and subject to mutation.
The Array.splice() method mutates its argument array. In the code, each varis[varis.length-1].splice() call modifies an array object that is copied from vari1 by reference, and therefore also vari0 whose elements are array objects that are copied to vari1 by reference. This is what causes vari to mutate.
To avoid the issue, use one these patterns:
var vari1 = vari0.map(row => row.slice()).filter(r => r[vstat]);
or
var vari1 = vari0.map(row => row.map(value => value)).filter(r => r[vstat]);
The patterns use Array.map() and Array.slice()to get a shallow copy of the 2D array referenced by vari0 (i.e., vari).
The first map() creates a new array of that contains the rows of vari0. The rows are arrays and therefore mutable, so a slice() or another map() is required to copy the rows into new arrays as well.
Note that the copy is shallow, which means that only primitive values such as text strings and numbers are copied by value. Your comments indicate that the rows of vari only contain primitives, so the pattern will make a copy that is safe to modify and will not mutate vari. Were the rows of the vari 2D array contain yet more arrays or other objects, the would be copied by reference and therefore still be subject to mutation.
Note that Array.splice() and Array.slice() are very different from each other. The Array.splice() method mutates its argument array. The Array.slice() method creates a shallow copy of the array, and is in fact often used to safely copy 1D arrays that contain primitives. In your use case, the vari array does not contain primitives but arrays, so we need to call slice() within map() to copy the primitive values in the second level of the 2D array.
In the general case, deep cloning an array or another object is surprisingly complex. The patterns above are probably the simplest way to do it in your use case. See What is the most efficient way to deep clone an object in JavaScript?

Why we can not empty Float32Array() array by assigning length equal to zero, like other normal array? In Javascript

Let's suppose we have two arrays.
var normal = new Array(1,2,3,4);
var float32 = new Float32Array(4);
Now its possible to empty normal array by
normal.length = 0;
But, In the case of float32 I am unable to empty array by
float32.lenght = 0;
Array remains same. why??
Because your Float32Array is just a view over an underlying ArrayBuffer, which itself is a fixed-length raw binary data buffer.
At the risk of simplifying a bit, once an ArrayBuffer has been assigned memory slots, it will stay in the same slots, and you won't be able to modify its byteLength*.
*Actually, you can empty the object which holds the data, by transferring its data, even if transferring it just for emptying the ArrayBuffer object makes no sense since you won't be able to change its length again (no push):
var arr = new Float32Array(56);
console.log('before transfer', arr.length);
postMessage(arr, '*', [arr.buffer]);
console.log('after transfer', arr.length);
Array remains same. why??
Float32Array is a TypedArray and as per docs
The length property is an accessor property whose set accessor
function is undefined, meaning that you can only read this property.
hence even after setting the length property to 0, its value remain as is
var arr = new Float32Array([21,31]);
arr.length = 0;
console.log(arr.length) //2
This might be a bit controversial but...
This state of affairs exists because the typed arrays are not generally meant for use by JavaScript developers. They are there to make JavaScript a more attractive target for compilers like emscripten.
Arrays in C/C++ are fixed-size (which is why you declare the size in bytes of those arrays when you create them in JS) and can only hold elements of a single type, so the idea of altering their length makes no sense and would invalidate a lot of the assumptions that C/C++ compilers get to make because of it.
The whole point of having typed arrays is to allow faster computations for expensive processes (e.g. 3D graphics) and if you had to check every access for an out-of-bounds access it would be too slow.

Values of variables with negative and big array indexes does not save in local storage

I have variable with uncommon array indexes. Here it is:
http://i.imgur.com/01nH8x5.png
So, I save it into local storage:
function Save(){
var save = {
//<...>
MapCellData: MapCellData,
MapCellDataE: MapCellDataE
//<...>
};
localStorage.setItem("save",JSON.stringify(save));
}
window.setInterval(function(){
Save()
}, 10000); // Autosave every 10 sec
Then I go to Firebug console and check what elements were saved by entering the following command:
JSON.parse(localStorage.getItem("save"));
This is what I get: http://i.imgur.com/vva3mBk.png
As you see, all values of variable with negative indexes and big indexes became undefined while indexes from 0 to 4 were saved properly.
Note: MapCellData is variable which determines which image will be applied to the table cell, and MapCellDataE is variable which determines cell background colour. Both of these variables have same indexes, so both share the same problem. Variables that does not have so strange indexes saves properly.
This is how it looks visually.
Before I reload a page: http://i.imgur.com/B3FSu5e.png
After I reload a page: http://i.imgur.com/rhkZAa1.png
Yes, JSON.stringify does only serialise array indices1 on Array objects, and discards all other properties. The solution is trivial - don't use arrays when you shouldn't be using them:
var MapCellData = {}; // instead of []
MapCellData[weirdProperty] = …;
This will be much more space-efficient in JSON as well, given how sparse your "array" is.
1: §6.1.7, §9.4.2: An array index is a String-valued property key that is a canonical numeric String and whose numeric value i is in the range +0 ≤ i < 232−1.

Iterate over jQuery JSON object in Chrome its changing the order

Jquery + rails 4
In json_data instance i have some data with key and value, The key is an integer id and the value is an object which contains data.However when I try to iterate over this data with the jQuery $.each function, the results come back sorted by the key instead.How can I iterate over my collection of objects in their original order?
$.each(json_data, function(key, value){
console.log(key);
});
key = 6181 30654 39148 30743 30510 42998 5788 30401 ...//Mozilla Working Fine (Right)
key = 5788 6011 6181 30401 30510 30639 30654 30698 30743 ...// Chrome Not Working Fine (Wrong)
Regarding "order" in an object:
A JavaScript object is a hash table, and is optimized for constant time lookup of key:value pairs.
Arrays are a data structure in which the elements are assigned to a discrete index value. When you iterate over the elements of an array, you will return a predictable pattern that matches the order of the items in the array.
In an object however, there are no index values, so there is no constant predictable way to iterate over it in order. The object just stores key:value pairs that are optimized for constant-time lookup.
EDIT: I will demonstrate those two methods of iterating just for illustration, but I wanted to warn you in advance, they won't change the fact that you won't get the keys returned in a consistent order.
var json_data = {6181:true, 30654:true, 39148:true, 30743:true, 30510:true, 42998:true, 5788:true, 30401:true};
for(item in json_data){
console.log(item);
} // *might* return a different order based on browser or JavaScript implementation
Clarifying one more time: objects are not associated with a particular 'order'. They are optimized to provide "constant time" lookup. Regardless of the size of the object, if you query a key, the associated value will be returned to you in constant time.
If you need to impose a particular order, you will need to use an array.
Example:
var json_data = [6181, 30654, 39148, 30743, 30510, 42998, 5788, 30401];
for(var i = 0; i < json_data.length; i++){
console.log(json_data[i]);
}
// always returns the values in the same order they are in the json_data array.
// changing the order in the array will change the order they are output and
// and that order will be the same regardless of which browser or version of JavaScript you
// are using.

What is a good way to create a JavaScript array with big indices?

I'm making a web app where a user gets data from PHP, and the data consists of MySQL rows, so I want to save the used ones in a global variable, something like a buffer, to prevent extra AJAX requests.
I'm doing this right now :
window.ray = []; // global variable
$(function(){
data = getDataWithAjax(idToSearch);
window.ray[data.id] = data.text;
});
but when the id is big, say 10 for now, window.ray becomes this :
,,,,,,,,42
so it contains 9 unnecessary spots. Or does it? Is it only visible when I'm doing console.log(window.ray);
If this is inefficient, I want to find a way like PHP, where I can assign only indices that I want, like :
$array['420'] = "abc";
$array['999'] = "xyz";
Is my current way as efficient as PHP, or does it actually contain unnecessary memory spots?
Thanks for any help !
Use an object instead of an array. The object will let you use the id as the key and be more efficient for non-sequential id values.
window.ray = {}; // global variable
$(function(){
data = getDataWithAjax(idToSearch);
window.ray[data.id] = data.text;
});
You can then access any element by the id:
var text = window.ray[myId];
If you are assigning values directly by property name, then it doesn't make any difference in terms of performance whether you use an Array or an Object. The property names of Arrays are strings, just like Objects.
In the following:
var a = [];
a[1000] = 'foo';
then a is (a reference to) an array with length 1,001 (always at least one greater than the highest index) but it only has one numeric member, the one called '1000', there aren't 1,000 other empty members, e.g.:
a.hasOwnProperty['999']; // false
Arrays are just Objects with a special, self–adjusting length property and some mostly generic methods that can be applied to any suitable object.
One feature of sparse arrays (i.e. where the numeric properties from 0 to length aren't contiguous) is that a for loop will loop over every value, including the missing ones. That can be avoided and significant performance gains realised by using a for..in loop and using a hasOwnProperty test, just like an Object.
But if you aren't going to use any of the special features of an Array, you might as well just use an Object as suggested by jfriend00.

Categories

Resources