iterate through a map in javascript
JavascriptJqueryMapJavascript Problem Overview
I have a structure like this:
var myMap = {
partnr1: ['modelA', 'modelB', 'modelC'],
partnr2: ['modelA', 'modelB', 'modelC']
};
I am going to iterate through each of the elements (partnr) with their associatives (models).
I am trying a double $each iteration in order to achieve this, but nothing happens:
$.each(myMap, function (i, val) {
$.each(i, function (innerKey, innerValue) {
setTimeout(function () {
$('#variant').fadeOut("slow", function () {
$(this).text(innerKey + "-" + innerValue).fadeIn("slow");
});
}, i * 6000);
});
});
The effect with fading in and out that I am trying to achieve is working fine when using a single value array (Object), but not when I need to have more than one value for each key like here.
Any ideas of how to accomplish this iteration succesfully and are there other ways than using a map that would be better in this case ?
Any suggestions would be of interest.
Javascript Solutions
Solution 1 - Javascript
An answer to your Question from 2019:
It depends on what version of ECMAScript you use.
Pre ES6:
Use any of the answers below, e.g.:
for (var m in myMap){
for (var i=0;i<myMap[m].length;i++){
... do something with myMap[m][i] ...
}
}
For ES6 (ES 2015):
You should use a Map
object, which has the entries()
function:
var myMap = new Map();
myMap.set("0", "foo");
myMap.set(1, "bar");
myMap.set({}, "baz");
for (const [key, value] of myMap.entries()) {
console.log(key, value);
}
For ES8 (ES 2017):
Object.entries()
was introduced:
const object = {'a': 1, 'b': 2, 'c' : 3};
for (const [key, value] of Object.entries(object)) {
console.log(key, value);
}
Solution 2 - Javascript
I'd use standard javascript:
for (var m in myMap){
for (var i=0;i<myMap[m].length;i++){
... do something with myMap[m][i] ...
}
}
Note the different ways of treating objects and arrays.
Solution 3 - Javascript
Functional Approach for ES6+
If you want to take a more functional approach to iterating over the Map
object, you can do something like this
const myMap = new Map()
myMap.forEach((value, key) => {
console.log(value, key)
})
Solution 4 - Javascript
The callback to $.each()
is passed the property name and the value, in that order. You're therefore trying to iterate over the property names in the inner call to $.each()
. I think you want:
$.each(myMap, function (i, val) {
$.each(val, function(innerKey, innerValue) {
// ...
});
});
In the inner loop, given an object like your map, the values are arrays. That's OK, but note that the "innerKey" values will all be numbers.
edit — Now once that's straightened out, here's the next problem:
setTimeout(function () {
// ...
}, i * 6000);
The first time through that loop, "i" will be the string "partnr1". Thus, that multiplication attempt will result in a NaN
. You can keep an external counter to keep track of the property count of the outer map:
var pcount = 1;
$.each(myMap, function(i, val) {
$.each(val, function(innerKey, innerValue) {
setTimeout(function() {
// ...
}, pcount++ * 6000);
});
});
Solution 5 - Javascript
Well, it looks like this old JQuery thread has been coopted by ES6 Map users.
If this is what you're looking for, may I suggest using the Array.from()
function which converts the Map
to an Array
. This allows you to easily chain transforms such as filter()
, map()
, etc.
const map = new Map([
['key one', 'value one'],
['key two', 'value two'],
]);
// Loop through key-value-pairs
Array.from(map.entries()).map(([key, val]) => console.log(key, val));
// Loop through map keys
Array.from(map.keys()).map(key => console.log(key));
// Loop through values
Array.from(map.values()).map(value => console.log(value));
Solution 6 - Javascript
Don't use iterators to do this. Maintain your own loop by incrementing a counter in the callback, and recursively calling the operation on the next item.
$.each(myMap, function(_, arr) {
processArray(arr, 0);
});
function processArray(arr, i) {
if (i >= arr.length) return;
setTimeout(function () {
$('#variant').fadeOut("slow", function () {
$(this).text(i + "-" + arr[i]).fadeIn("slow");
// Handle next iteration
processArray(arr, ++i);
});
}, 6000);
}
Though there's a logic error in your code. You're setting the same container to more than one different value at (roughly) the same time. Perhaps you mean for each one to update its own container.
Solution 7 - Javascript
We can use forEach Method available on maps From ES6 Version.
var myMap =new Map([
["partnr1", ['modelA', 'modelB', 'modelC']],
["partnr2", ['modelA', 'modelB', 'modelC']]
]);
myMap.forEach(function(values,key){
console.log(key);
/*****Do something with the models***********/
for(const [index,value] of values.entries()){
console.log(` ${key}[${index}] : ${value}`);
}
});
Solution 8 - Javascript
This is easily achieved using a javascript Map
object. You simply iterate over the Map
, using the fact that the map you're iterating over is included as an argument in each iteration call. Notice the map
argument in the forEach
function. This is the same Map
object you're iterating over.
// Define the map
const myMap = new Map([
["key1", "value 1"],
["key2": "value 2"],
["key3": "value 3"]
])
// Iterate over the map, updating each value
myMap.forEach((value,key,map) => {
map.set(key, value + "A")
})
/*
Result: myMap now looks like this:
[
["key1", "value 1A"],
["key2": "value 2A"],
["key3": "value 3A"]
]
/*