Is it possible to add a new element to top of Map without sorting?
Like as unshift()
?
Because Map is it like a object, I each time sort object after adding operation.
I have done this like that:
let map = new Map(); map.set(1, { id: 1 }); map.set(2, { id: 2 }); map.set(3, { id: 3 }); map.set(4, { id: 4 }); let mapCopy = new Map(); for (let i = map.size; i > 0 ; --i) { mapCopy.set(i, map.get(i)); } console.log(map); console.log(mapCopy);
Advertisement
Answer
A Map preserves the insertion order of keys by specification:
const map = new Map(); map.set(3, "gamma"); map.set(1, "alpha"); map.set(2, "beta"); print(map); function print(map) { for ([key, value] of map.entries()) console.log(`${key} - ${value}`) }
If you want to move something to the end, it has to be the last inserted item. You can “move” by deleting and re-adding:
const map = new Map(); map.set(3, "gamma"); map.set(1, "alpha"); map.set(2, "beta"); moveToEnd(map, 3); print(map); function print(map) { for ([key, value] of map.entries()) console.log(`${key} - ${value}`) } //modifies in-place function moveToEnd(map, key) { //save value const value = map.get(key); //delete map.delete(key); //re-insert map.set(key, value); }
Note that you must delete, otherwise it doesn’t work:
const map = new Map(); map.set(3, "gamma"); map.set(1, "alpha"); map.set(2, "beta"); moveToEnd(map, 3); print(map); function print(map) { for ([key, value] of map.entries()) console.log(`${key} - ${value}`) } //modifies in-place function moveToEnd(map, key) { //save value const value = map.get(key); //don't delete //re-insert map.set(key, value); }
Another option is to re-create the entire Map and enforce the new insertion order:
const map = new Map(); map.set(3, "gamma"); map.set(1, "alpha"); map.set(2, "beta"); const newMap1 = moveToEnd1(map, 3); const newMap2 = moveToEnd2(map, 3); print(newMap1); console.log("------") print(newMap2); function print(map) { for ([key, value] of map.entries()) console.log(`${key} - ${value}`) } function moveToEnd1(map, key) { //create a new Map from the old one const result = new Map(map); //save value const value = map.get(key); //delete result.delete(key); //re-insert result.set(key, value); return result; } function moveToEnd2(map, key) { return [...map.entries()] //get all entries .filter(([k,]) => k !== key) //remove all but the key that would be last .reduce( //create a new Map inserting all other entries (acc, [key, value]) => acc.set(key, value), new Map() ) .set(key, map.get(key)); //add the last entry }
However, a move to front means that you have to shift everything else to the front. Again, you can do the same as before – either move the entries in-place by deleting and re-adding the keys:
const map = new Map(); map.set(3, "gamma"); map.set(1, "alpha"); map.set(2, "beta"); const newMap1 = moveToFront(map, 1); print(map); function print(map) { for ([key, value] of map.entries()) console.log(`${key} - ${value}`) } function moveToFront(map, key) { //materialise all entries, because the iterator provides a live view const entries = Array.from(map.entries()); //move to the back for (let [k, v] of entries) { //skip moving the target key if (k === key) continue; //delete map.delete(k); //re-insert map.set(k, v); } }
Or re-create the map with the new order. Note that if you insert the desired key in front, you can just use set
again with it and it won’t move, as long as there is no .delete()
called for it, which makes the re-creation easier:
const map = new Map(); map.set(3, "gamma"); map.set(1, "alpha"); map.set(2, "beta"); const newMap = moveToFront(map, 1); print(newMap); function print(map) { for ([key, value] of map.entries()) console.log(`${key} - ${value}`) } function moveToFront(map, key) { return new Map([ [key, map.get(key)], //key-value to be in front ...map //merge with the entire map ]); }
As for actually adding instead of moving – the same applies, you can either shift everything in the map or just re-create it. Assuming you want to treat a repeat inset as “move to front”, then you can do something like this:
const map = new Map(); map.set(3, "gamma"); map.set(1, "alpha"); map.set(2, "beta"); addToFrontInPlace(map, 4, "delta"); print(map); console.log("-------"); addToFrontInPlace(map, 1, "new alpha"); print(map); function print(map) { for ([key, value] of map.entries()) console.log(`${key} - ${value}`) } function addToFrontInPlace(map, key, value) { //add new value map.set(key, value); //materialise all entries, because the iterator provides a live view const entries = Array.from(map.entries()); //move to the back for (let [k, v] of entries) { //skip moving the target key if (k === key) continue; //delete map.delete(k); //re-insert map.set(k, v); } }
const map = new Map(); map.set(3, "gamma"); map.set(1, "alpha"); map.set(2, "beta"); const newMap1 = addToFrontNewMap(map, 4, "delta"); print(newMap1); console.log("-------"); const newMap2 = addToFrontNewMap(newMap1, 1, "new alpha"); print(newMap2); function print(map) { for ([key, value] of map.entries()) console.log(`${key} - ${value}`) } function addToFrontNewMap(map, key, value = 7) { //exclude the entry from the old map, so it doesn't overwrite the value const entries = [...map.entries()] .filter(([k,]) => k !== key); return new Map([ [key, value], //key-value to be in front ...entries //merge with the entire map ]); }