0

I have a Map object that looks like so:

const myMap = new Map();
myMap.set('a', 1);
myMap.set('b', 2);
myMap.set('c', 3);
myMap.set('d', 4);

I would need to be able to reorder that, so that, having a specific key, this key would be first, those keys originally following it should follow as before, and those originally preceding it will be placed at the end with their original order.

An example with arrays:

const key = 'c';
const pre = ['a','b','c','d'];
const post = ['c','d','a','b'];

Another example:

const key = 'd';
const pre = ['a','b','c','d'];
const post = ['d','a','b','c'];

Yet another:

const key = 'a';
const pre = ['a','b','c','d'];
const post = ['a','b','c','d'];

I guess I should take the keys with myMap.keys() and rebuild my map, buy my brain is really struggling to find out how to deal with it to achieve what I want....

Any hints would be greatly appreciated.

umbe1987
  • 2,894
  • 6
  • 35
  • 63
  • Does this answer your question? [Is it possible to sort a ES6 map object?](https://stackoverflow.com/questions/31158902/is-it-possible-to-sort-a-es6-map-object) – ysfaran Mar 20 '21 at 21:09
  • Not really, but thanks anyway ;). I am not trying to sort it, I am trying to reorder it with a specific order. – umbe1987 Mar 20 '21 at 21:10
  • It is a long long time ago that I worked with TypeScript. But can't you reasign the numbers? And than do a sort? – M1sterPl0w Mar 20 '21 at 21:11
  • @Wendelin Well, I am talking about the insertion of its elements. AFAIK, when getting a Map's keys, they are ordered like they were inserted. – umbe1987 Mar 20 '21 at 21:12
  • Also, from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map: "The keys in Map are ordered in a simple, straightforward way: A Map object iterates entries, keys, and values in the order of entry insertion." – umbe1987 Mar 20 '21 at 21:14
  • What is your higher level use case for needing to do this? I can think of several ways of either creating array of keys in different order or storing an object for each key value instead of just a primitive that tracks both order and value – charlietfl Mar 20 '21 at 21:30
  • @charlietfl long story short: I am using this library (https://www.colyseus.io/) to create a game for my friends (https://github.com/umbe1987/striscioline). Each player answers a set of questions (same question for each). Then the questions are "shuffled" to make interesting and funny QA. This shuffled QA has to be unique for each player at the end. colyseus use Map objects. – umbe1987 Mar 20 '21 at 21:44

4 Answers4

2

This seems to work:

let reorder = (map, keys) =>
    new Map(keys.map(k => [k, map.get(k)]))


let rotate = (ary, n) =>
  ary.slice(n).concat(ary.slice(0, n))


const myMap = new Map();
myMap.set('a', 1);
myMap.set('b', 2);
myMap.set('c', 3);
myMap.set('d', 4);


keys = [...myMap.keys()]
newMap = reorder(myMap, rotate(keys, keys.indexOf('c')))
console.log([...newMap.entries()])
georg
  • 211,518
  • 52
  • 313
  • 390
2

Great challengue! I really enjoyed doing it!

here is my approach:

function orderMyMap(myMap, key) {
    const array = Array.from(myMap)
    return [...array.splice(array.findIndex((arr) => arr[0] === key), array.length), ...array];
}

If you want a map instead an array as reponse just add:

function orderMyMap(myMap, key) {
    const array = Array.from(myMap)
    const newArray = [...array.splice(array.findIndex((arr) => arr[0] === key), array.length), ...array];

    const newMap = new Map();
    
    newArray.map(values=>{
        newMap.set(values[0],values[1])
    })
    return newMap
}
  • 1
    thank you so much. This works indeed very well! I accepted the other answer because it worked and it was provided before yours... I really appreciate your effort and I wish I could accept two answers;) Anyway, really appreciate you took the time to help me – umbe1987 Mar 20 '21 at 21:41
0

One solution for this could be that you will first save the [key, value] that you wish to reorder, then remove it from your map, and then construct a new one by putting the saved value at the beginning.

Example with arrays:

const key = 'd';
const keys = ['a', 'b', 'c', 'd'];
// remove the last occurence of the key from array
keys.splice(keys.lastIndexOf(key), 1);
// add new element at the beginning
keys.unshift(key);

Splice Removes elements from the array starting at the given position and number of elements provided as the second argument.

Unshift Adds a new element at the beginning of the array

One possible solution for your problem:

// First store the keyValue element you're going to reorder
const keyValue = [key, myMap.get(key)];
// Remove from initial map the key element
myMap.delete(key);
// Make a new map from what you have
myMap = new Map([keyValue, ...myMap]);

You can make a new Map passing an array to the constructor, which will result in the correct order that you wish. While this solution might look not very optimal, however, its performance is still relatively good, because getting and removing elements is O(1), but the only thing is that you're going to rebuild a new Map object every time which will cause O(n).

Miraziz
  • 509
  • 7
  • 15
0

const myMap = new Map();
myMap.set('a', 1);
myMap.set('b', 2);
myMap.set('c', 3);
myMap.set('d', 4);

function sortByKey(map, key){
  if(map.size <= 1) return map;

  const entries = [...map.entries()];
  const index = entries.findIndex(entry => entry[0] === key);
  return new Map([entries[index], ...entries.slice(index + 1, entries.length), ...entries.slice(0, index)]);
}

console.log('a', [...sortByKey(myMap, 'a').keys()]);
console.log('b', [...sortByKey(myMap, 'b').keys()]);
console.log('c', [...sortByKey(myMap, 'c').keys()]);
console.log('d', [...sortByKey(myMap, 'd').keys()]);
ysfaran
  • 5,189
  • 3
  • 21
  • 51