Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript Map ordering

i recently had a bug in my code that was due to me missing the "in insertion order" text while looking through Map object details on MDN. In short, i have a map object, lets say

let myMap = new Map;

and then, after populating it, i iterate over its contents with a simple for .. of statement. Like this

for (let [key, val] of myMap) { 
    ...
}

The code in for loop depends on (key, value) pair to be sorted by key. However the algorithm that populates the map, does so in a random order(and i can't change that). To get around this problem, i now add all possible keys to the map object first, something like this:

let myMap = new Map;
for (let i=0; i<maxkey; ++i) myMap.set(key(i), undefined);

// And in the for loop
for (let [key, val] of myMap) {
    if (typeof val === "undefined") continue;
    //...
}

Fortunately, there aren't many of them(so the performance penalty is negligible), and this works. Still this solution looks a bit awkward to me.

Is there something better?

like image 920
Pavel Beliy Avatar asked Feb 22 '26 06:02

Pavel Beliy


2 Answers

According to mozilla javascript reference here

A Map object iterates entries, keys, and values in the order of entry insertion.

so you should sort the keys before insert them into the map, then you can iterate the map in key order.

like image 52
wsysuper Avatar answered Feb 24 '26 19:02

wsysuper


The code in for loop depends on (key, value) pair to be sorted by key.

Then a Map is the wrong data structure for you. Its purpose is fast lookup, not maintaining an order. If you need an ordered (sortable) sequence, use an array. Or if you need both lookup and custom order, then use both in combination. For your particular case with a small number of known keys, pre-populating the map is fine, alternatively use them only for the iteration

for (let key=0; key < maxkey; key++) {
    if (myMap.has(key)) {
        const val = myMap.get(key);
        … // use key and value
    }
}

Or if there are much more keys than stored in the map, you can also do

for (const key of Array.from(myMap.keys()).sort((a, b) => a-b)) {
    const val = myMap.get(key);
    … // use key and value
}

If you have to do this more than once, you might also want to implement your own iterator.

like image 28
Bergi Avatar answered Feb 24 '26 20:02

Bergi