Iterating over sparse arrays [duplicate] - javascript

This question already has answers here:
How should I iterate over a sparse array in index order?
(2 answers)
Closed 6 years ago.
This answer says that the best way to iterate over sparse arrays is to use for X in Array
However, when I tried this I tripped up because the type of X was a string, rather than the integer index I was expecting. (All fine until I added it to another integer...)
var arr = [];
arr[10000] = "Hello";
var shifted = []
for (var x in arr)
shifted[10+x] = arr[x];
"Expected":
shifted[10010] = "Hello
Actual
shifted["1010000"] = "Hello"
Is there a better way of iterating a sparse array using the index, or should I just use Number(X) where required?

This is how V8 (and others JavaScript engines) handles arrays:
V8 uses two different methods to handle arrays:
Fast elements:
Designed for arrays where set of keys are very compact. They have a linear storage buffer that can be accessed very efficiently.
Dictionary elements:
Designed for sparse arrays which don’t have every elements inside of them. It is actually a hash table, more expensive to access than “Fast Elements”
Source: http://thibaultlaurens.github.io/javascript/2013/04/29/how-the-v8-engine-works/
When you are using a sparse array, the key is converted to string and then hashed. If you want numeric keys: don't use a sparse array or manually convert the key to a number.

Related

Why Do I Get a Stack Overflow When Base Case Compares an Empty Array [duplicate]

This question already has answers here:
How to compare arrays in JavaScript?
(61 answers)
Why are two identical objects not equal to each other?
(9 answers)
Closed 2 years ago.
I started with:
"1:2".split(':') == ["1","2"];
// false
Then tried:
[1,2] == [1,2];
// false
and ultimately:
[] == [];
// false
I've since found that:
"1:2".split(':').toString() == [1,2].toString();
// true
So I've solved my initial issue (kind of) but why can't arrays match each other?
Javascript arrays are objects and you can't simply use the equality operator == to understand if the content of those objects is the same. The equality operator will only test if two object are actually exactly the same instance (e.g. myObjVariable==myObjVariable, works for null and undefined too).
If you need to check if two array are equals i'd recommend to just traverse both arrays and verify that all the elements have the same value (and that the two array have the same length).
Regarding custom objects equality i'd build instead a specific equals function and i'd add it to the prototype of your class.
Considering that in the end you converted both arrays to a String and tested equality of the resulting strings, you could one day consider using a similar but more generic technique you'll find described in more than a few places:
JSON.stringify(OBJ1) === JSON.stringify(OBJ2)
Well, don't.
While this could work if the order of the properties will always the same for those object instances, this leaves the door open for extremely nasty bugs that could be hard to track down. Always favor a more explicit approach and just write a clean and readable function that will test for equality checking all the required fields.
The == operator for Objects in Javascript only checks to see if the objects are the same actual object reference, not if they are two separate object that contain the same contents. There is no built in operator for checking if they contain the same contents. You would have to write a function to do that sort of comparison yourself.
Your string conversion is one way of comparing two arrays as long as the array elements only contain primitive values (not other objects). If the array elements could contain other elements, then you would have to make sure those objects were themselves converted into representative strings too.
And, converting to a string would not discern between an array element that contains "4" versus one that contains 4 since both convert to "4" in the string representation.
FYI, you can read in this answer about records and tuples, two new data types coming to future Javascript that will allow comparing an immutable version of arrays and objects by value instead of by only comparing to see if they are the same object.
Equality for objects will tell you if the two objects are the same one.
var a = [];
var b = a;
a === b; // True, a and b refer to the same object
[] === []; // False, two separate objects
You will have to loop through the arrays to see if they have the same elements.
See: How to check if two arrays are equal with JavaScript?
In javascript each [] is an instance of window.Array class. So you are basically trying to compare two different objects. Since array's can have any no. and any type of elements including Objects and Custom Objects and those nested arrays can again have numerous properties and arrays and so on.
It becomes ambiguous when it comes to comparison, you will never be sure what do you want to do with those objects and nested properties. So what you are trying to achieve by comparing can be done in so many other ways. You just have to figure out the right way for your case.
One way is to make your own Array checking function:
How to compare arrays in JavaScript?!
Another way is to convert the Array to a String with .join(), and compare the strings. Then convert them back into Arrays with .split().
If I relate this problem with that in Python:
Input:
a="1 2 3 4"
case I:
a=input.split(' ')
output: ['1', '2', '3', '4']
case II:
a=map(int,input.split(' '))
output: [1, 2, 3, 4]
So, the fault is that of type, as it could come-out aa 'true' for:
"1:2".split(':').toString() == [1,2].toString(); //true

How do I get the value of the key if the key in the Map is an array? [duplicate]

This question already has answers here:
How to compare arrays in JavaScript?
(55 answers)
Why are two identical objects not equal to each other?
(9 answers)
Closed 2 years ago.
I started with:
"1:2".split(':') == ["1","2"];
// false
Then tried:
[1,2] == [1,2];
// false
and ultimately:
[] == [];
// false
I've since found that:
"1:2".split(':').toString() == [1,2].toString();
// true
So I've solved my initial issue (kind of) but why can't arrays match each other?
Javascript arrays are objects and you can't simply use the equality operator == to understand if the content of those objects is the same. The equality operator will only test if two object are actually exactly the same instance (e.g. myObjVariable==myObjVariable, works for null and undefined too).
If you need to check if two array are equals i'd recommend to just traverse both arrays and verify that all the elements have the same value (and that the two array have the same length).
Regarding custom objects equality i'd build instead a specific equals function and i'd add it to the prototype of your class.
Considering that in the end you converted both arrays to a String and tested equality of the resulting strings, you could one day consider using a similar but more generic technique you'll find described in more than a few places:
JSON.stringify(OBJ1) === JSON.stringify(OBJ2)
Well, don't.
While this could work if the order of the properties will always the same for those object instances, this leaves the door open for extremely nasty bugs that could be hard to track down. Always favor a more explicit approach and just write a clean and readable function that will test for equality checking all the required fields.
The == operator for Objects in Javascript only checks to see if the objects are the same actual object reference, not if they are two separate object that contain the same contents. There is no built in operator for checking if they contain the same contents. You would have to write a function to do that sort of comparison yourself.
Your string conversion is one way of comparing two arrays as long as the array elements only contain primitive values (not other objects). If the array elements could contain other elements, then you would have to make sure those objects were themselves converted into representative strings too.
And, converting to a string would not discern between an array element that contains "4" versus one that contains 4 since both convert to "4" in the string representation.
FYI, you can read in this answer about records and tuples, two new data types coming to future Javascript that will allow comparing an immutable version of arrays and objects by value instead of by only comparing to see if they are the same object.
Equality for objects will tell you if the two objects are the same one.
var a = [];
var b = a;
a === b; // True, a and b refer to the same object
[] === []; // False, two separate objects
You will have to loop through the arrays to see if they have the same elements.
See: How to check if two arrays are equal with JavaScript?
In javascript each [] is an instance of window.Array class. So you are basically trying to compare two different objects. Since array's can have any no. and any type of elements including Objects and Custom Objects and those nested arrays can again have numerous properties and arrays and so on.
It becomes ambiguous when it comes to comparison, you will never be sure what do you want to do with those objects and nested properties. So what you are trying to achieve by comparing can be done in so many other ways. You just have to figure out the right way for your case.
One way is to make your own Array checking function:
How to compare arrays in JavaScript?!
Another way is to convert the Array to a String with .join(), and compare the strings. Then convert them back into Arrays with .split().
If I relate this problem with that in Python:
Input:
a="1 2 3 4"
case I:
a=input.split(' ')
output: ['1', '2', '3', '4']
case II:
a=map(int,input.split(' '))
output: [1, 2, 3, 4]
So, the fault is that of type, as it could come-out aa 'true' for:
"1:2".split(':').toString() == [1,2].toString(); //true

Javascript associative array does not support Array.prototype.map function [duplicate]

This question already has answers here:
Length of a JavaScript associative array
(4 answers)
Closed 4 years ago.
After long times programming, I don't know why never have seen this:
var array = [];
array['one'] = 1;
console.log(array.length);
Here is a fiddle that shows array.length is zero (0):
https://jsfiddle.net/0c9v5txe/1/
Of-course, I don't need the length of array, just array.map is not working when the length is zero.
Isn't there really a way to force Javascript update the length of an associative array when adding a new item?
JavaScript doesn't have a feature called "associative arrays".
It has objects, and arrays are a type of object designed to hold numerically indexed values. (The length property on an array is calculated based on the highest numbered numerical property).
(Since arrays are a type of object, you can store arbitrary properties on them, but this is not a good practice).
If you want to store named properties, then do not use an array. Use a plain object or a Map. These serve the same purposes as associative arrays in other languages.
You can count the enumerated properties of an object by extracting them into an array and then checking its length.
var myObject = {};
myObject.one = 1;
console.log(Object.keys(myObject).length);
you need to pass index, not value
array[index] = value;
var array = [];
array[0] = "one";
console.log(array.length)

How to sort object elements in javascript? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Sorting a JavaScript object
Sort JavaScript object by key
I have array:
var arr = {}
arr[2323] = 1
arr[123] = 1
...
arr[n+232323] = 1
How to get all element of aobject sorted by key ( number order ? )
for ( key in arr ) {
alert(typeof(key))
}
return string type.
This is not an assosiative array, this is an object. There are no associative arrays in javascript.
Additionally, objects are not ordered. The order of keys in an object is meaningless.
Assuming there's some reason you don't use an Array in the first place, you can get an Array of the enumerable object properties, and sort that Array...
var sorted = Object.keys(my_obj)
.sort(function(a,b) {
return a - b;
});
This assumes the keys are numeric.
Then you can iterate the Array, and use each key to get the value from my_obj...
sorted.forEach(function(key) {
console.log(my_obj[key]);
});
Short answer: You can't.
Long answer: Associative Arrays in JavaScript are really JavaScript objects. When you add a new element, you're really adding a new member to the object. While most browsers will enumerate those members in the order they were added, the standard states that the order is undefined. You can't sort something that is undefined.
JavaScript objects (maps/dictionaries/associative arrays) have no order, you can't sort them. You will need to convert it to an array first. As you only need the keys of your object in your loop, the Object.keys() function (potentionally needs a shim for older browsers) is destined for the task:
var obj = {...};
var keys = Object.keys(obj).sort(function(a,b){return a-b;}); // numerically sorted
for (var i=0; i<keys.length; i++) {
alert(keys[i]);
// access the values by obj[keys[i]]
}

JavaScript For-each/For-in loop changing element types [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
JavaScript “For …in” with Arrays
I'm trying to use the for-in syntax to loop through an array of numbers. Problem is, those numbers are getting converted to strings.
for(var element in [0]) {
document.write(typeof(element)); // outputs "string"
}
Is this standard behavior? I can think of a bunch of ways to work around it, but I'm really just looking for an explaination, to expand my understanding of JavaScript.
I think you misunderstand what JavaScript for...in does. It does not iterate over the array elements. It iterates over object properties. Objects in JavaScript are kind of like dictionaries or hashes in other languages, but keyed by strings. Arrays in particular are implemented as objects which have properties that are integers from 0 to N-1 - however, since all property names are strings, so are the indices, deep down.
Now let's take a bit different example than [0], since here index coincides with the value. Let's discuss [2] instead.
Thus, [2] is, if we ignore the stuff we inherit from Array, pretty much the same as { "0": 2 }.
for..in will iterate over property names, which will pick up the "0", not the 2.
Now, how to iterate over Arrays then, you ask? The usual way is:
var arrayLen = array.length;
for (var i = 0; i < arrayLen; i++) {
var el = array[i];
// ...
}
This is a repeat of Why is using "for...in" with array iteration a bad idea?
The for-in statement enumerates the properties of an object. In your case element is the name of the property and that is always a string.

Categories