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);
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");
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
]);
}