Why is this extremely basic JavaScript array giving me a length of 13 when there are only 3 key/value pairs in it. It makes sense that it might think 13 as 0 based index and my last array has a key of 12, but I need to have any array that has a key/value pair that returns me the correct number of pairs. The keys need to be numbers.
http://jsfiddle.net/fmgc8/1/
EDIT: this is how I solved it thanks.
http://jsfiddle.net/fmgc8/4/
it's because the highest number you have is:
array['12'] = 'twelve';
This creates an array length of 13 (since it's 0 based). JavaScript will expand the array to allocate the number of spots it needs to satisfy your specified slots. array[0..9] is there, you just haven't placed anything in them.
There is no diffrence between array['12'] and array[12] (array['12'] is not considered as associative array element). To find associative array length
The length property of arrays returns the biggest non-negative numeric key of the object, plus one. That's just the way it's defined.
If you want to count the key-value pairs, you're going to have to count them yourself (either by keeping track of them as they are added and removed, or by iterating through them).
Or, rearrange your array like this:
var array = [];
array.push(['10','ten']);
array.push(['11','eleven']);
array.push(['12','twelfe']);
alert(array.length);
Related
I need to loop through a JavaScript object treating it as an array with custom keys.
I know this is not fully supported, since properties have no instrinsic order, but since I always reorder the properties, I found this approach simple and reliable... until now.
The problem occurs when the keys are numbers, or strings that can be casted as numbers.
When I run this code:
var test1 = {4294966222:"A",4294966333:"A",4294966111:"A"};
var test2 = {4294968222:"A",4294968333:"A",4294968111:"A"};
for (var k in test1) {console.log(k);}
console.log("---");
for (var k in test2) {console.log(k);}
the output is:
4294966111
4294966222
4294966333
---
4294968222
4294968333
4294968111
Which means:
(test1) if the keys are below 2^32 (4,294,967,296), they are automatically reordered, the smallest first
(test2) if the keys are above 2^32, they are NOT reordered.
The question is: why is this happening?
Since all the browsers I tested (Google Chrome 79.0, Mozilla Firefox 71.0, Microsoft Edge 44.18362, Internet Explorer 11.535) agree about this output, there must be some official specification.
Update
I tested a lot of numbers before finding out it was a threshold matter. I found odd that the sequence 2,3,1 behaves differently from three timestamps ordered in the same way.
This is expected. Per the specification, the method that iterates over properties, OrdinaryOwnPropertyKeys, does:
For each own property key P of O that is an array index, in ascending numeric index order, do
a. Add P as the last element of keys.
For each own property key P of O that is a String but is not an array index, in ascending chronological order of property creation, do
a. Add P as the last element of keys.
The ascending numeric order only applies for properties which are array indicies.
So, what is an "array index"? Look it up::
An integer index is a String-valued property key that is a canonical numeric String (see 7.1.21) and whose numeric value is either +0 or a positive integer ≤ 2^53 - 1. An array index is an integer index whose numeric value i is in the range +0 ≤ i < 2^32 - 1.
So, numeric properties that are greater than 2^32 are not array indicies, and therefore iterated in order of property creation. However, numeric properties that are less than 2^32 are array indicies, and are iterated over in ascending numeric order.
So, for example:
1: Array index, will be iterated over numerically
10: Array index, will be iterated over numerically
4294968111: Greater than 2 ** 32, will be iterated over after array indicies are finished, in property creation order
9999999999999: Greater than 2 ** 32, will be iterated over after array indicies are finished, in property creation order
Also, keep in mind that, contrary to popular belief, property iteration order is guaranteed by the specification as well, thanks to the for-in iteration proposal which is stage 4.
This has to do with the way they keys of an object are traversed.
According to the ES6 specifications it should be:
9.1.12 [[OwnPropertyKeys]] ( )
When the [[OwnPropertyKeys]] internal method of O is called the following steps are taken:
Let keys be a new empty List.
For each own property key P of O that is an integer index, in ascending numeric index order
Add P as the last element of keys.
For each own property key P of O that is a String but is not an integer index, in property creation order
Add P as the last element of keys.
For each own property key P of O that is a Symbol, in property creation order
Add P as the last element of keys.
Return keys.
http://www.ecma-international.org/ecma-262/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys
That means if the value of a key stays the same if converted to an unsigned 53 bit number
and back it is treated as an integer index which gets sorted in ascending numeric order.
If this fails it's treated as a string key, which are ordered the way they were added
to the object.
The catch here is that all major browsers don't follow this specification yet
and use an array index instead which is limited to a positive number up to .
So anything above that limit is a string key actually.
So basically I have an array of n integers (positive only). I want to have k number of integers from this array into a separate array (k<n) such that the difference between these k numbers is the minimum amongst every other k pairs of integers in an array.
If k is 1, I just need to return the max integer of the array.
I want to implement this in JavaScript. I understand how to run this problem for the values k=1 and k=2. But I don't grasp the general concept of this problem.
For eg:
Array = [6,22,21,63,99,77]
I sorted this array in ascending order. After this I don't understand how to proceed further.
After sorting the array it becomes similar to a sliding window problem.
Run a loop from i=0 to n-k and check the following.
Find the minimum difference between arr[i+k] and arr[i]. The index at which this occurs is your subset of k integers you want.
You can check this link for more details and coding help.
I have an array like below
arr=[];
arr[0]={"zero": "apple"};
arr[1]={"one": "orange"};
arr["fancy"]="what?";
but i am getting length as 2 when i do console.log(arr.length) even though i am able to console all the values .
and not able to get all values while doing console.log(JSON.stringify(arr))
What is the issue here.
here is the link to fiddle fiddle
.length is a special property in Javascript arrays, which is defined as "the biggest numeric index in the array plus one" (or 2^32-1, whatever comes first). It's not "the number of elements", as the name might suggest.
When you iterate an array, either directly with for..of or map, or indirectly with e.g. JSON.stringify, JS just loops over all numbers from 0 to length - 1, and, if there's a property under this number, outputs/returns it. It doesn't look into other properties.
The length property don't work as one will expect on arrays that are hashtables or associative arrays. This property only works as one will expect on numeric indexed arrays (and normalized, i.e, without holes). But there exists a way for get the length of an associative array, first you have to get the list of keys from the associative array using Object.keys(arr) and then you can use the length property over this list (that is a normalized indexed array). Like on the next example:
arr=[];
arr[0]={"zero": "apple"};
arr[1]={"one": "orange"};
arr["fancy"]="what?";
console.log(Object.keys(arr).length);
And about this next question:
not able to get all values while doing console.log(JSON.stringify(arr))
Your arr element don't have the correct format to be a JSON. If you want it to be a JSON check the syntax on the next example:
jsonObj = {};
jsonObj[0] = {"zero": "apple"};
jsonObj[1] = {"one": "orange"};
jsonObj["fancy"] = "what?";
console.log(Object.keys(jsonObj).length);
console.log(JSON.stringify(jsonObj));
From MDN description on arrays, here, "Arrays cannot use strings as element indexes (as in an associative array) but must use integers."
In other words, this is not Javascript array syntax
arr["fancy"]="what?";
Which leads to the error in .length.
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.
I am using the following pattern to index an injection from pairs of numbers to numbers:
var myHash = {};
...
for (... billion of iterations ...)
var x = someNum;
var y = otherNum;
myHash[x + "," + y] = z;
The problem with this code is that I'm using a string as the key of myHash, which has been tested to be much slower than integer keys. My question is: what is a more intelligent way to combine 2 numbers before using them as keys of an object? I.E., how to combine 2 doubles into an unique Integer?
There is the definition of an array in JavaScript:
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. A property whose property name is an array index is also called an element. Every Array object has a length property whose value is always a nonnegative integer less than 232. The value of the length property is numerically greater than the name of every property whose name is an array index; whenever a property of an Array object is created or changed, other properties are adjusted as necessary to maintain this invariant. Specifically, whenever a property is added whose name is an array index, the length property is changed, if necessary, to be one more than the numeric value of that array index; and whenever the length property is changed, every property whose name is an array index whose value is not smaller than the new length is automatically deleted. This constraint applies only to own properties of an Array object and is unaffected by length or array index properties that may be inherited from its prototypes.
In other words, if the index you specify is a number representing an integer between 0 and 0xFFFFFFFE, then it is used as an array index. Any other value is taken as a string and it is used to create an object member instead of an array item.
So if you have constraints on your indices which would fit the valid range (0 to 0xFFFFFFFE) then you're good. Otherwise, what you have is probably the fastest.
So the following represents string indices which are members of object myHash:
myHash[x + "," + y] = z;
Someone mentioned using an array of arrays. That would not help you. You'd get many arrays instead of many strings. It would probably be about the same if not slower. The idea is something like this:
myHash[x] = []; // initialize the sub-array (must be done only once per value of 'x'
myHash[x][y] = z; // save z in that array
I do not recommend the double array because it will initialize one array for each value of 'x' on top of myHash and that probably not any faster than having the string concatenation (especially because you'll have to test whether the myHash[x] array was already defined or not...).
So... it is possible to write:
myHash[3.3] = "that worked?";
But if after that you check out the length, you'll notice it is zero:
console.log("Hash length = " + myHash.length);
This is because 3.3 is not an integer.