Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create a two-way mapping in JavaScript, or some other way to swap out values?

I currently have a need to temporarily swap out values in a JavaScript string, and therefore I will need to have a two-way map/hash thing.

For example, let's say I want to change \* to __asterisk__ (this is just an example, it's not what I'm actually trying to do). I'll have to be able to map * to __asterisk__ (to swap out the value in the original string), but then I'll also have to be able to map __asterisk__ back to * (to get the original string back).

Here's some quick pseudo-ish code of the kind of thing that I'm looking for, so you can understand it better:

var myString = 'this is \* a test';  // ??? var twoWayMap = new TwoWayMap('*' <---> '__asterisk__', '%' <---> '__percent__', ...);  var newString = myString.replace(/\\(.)/g, function(m, c) {     return twoWayMap.getKey(c); }); // newString is now 'this is __asterisk__ a test'  // ... later in the code ...  var oldString = newString.replace(/__([^_]+)__/g, function(m, c) {     return twoWayMap.getValue(c); }); // oldString is now 'this is * a test' 

This is what I've thought about and tried so far:

var twoWayMap = {'*': '__asterisk__', '%': '__percent__', ...};  // getKey would be like this: twoWayMap[c]; // getValue would be like: var val; for (var x in twoWayMap) { if (twoWayMap[x] === c) { val = x; break } } 

The obvious problem with this is that the way to get by value is much too complicated, and I don't want to have to write out the whole thing every single time I have to reverse lookup.

I just wanted to know: Is there any way to solve this problem without resorting to looping through an object? If not, is there any way to make it easier or cleaner?

like image 227
tckmn Avatar asked Jan 12 '14 03:01

tckmn


People also ask

How can use two map in JavaScript?

To merge Maps, use the spread operator (...) to unpack the values of two or more Maps into an array and pass them into the Map() constructor, e.g. new Map([... map1, ... map2]) . The new Map will contain the key-value pairs from all provided Map objects.

What are map methods in JavaScript?

map() creates a new array from calling a function for every array element. map() calls a function once for each element in an array. map() does not execute the function for empty elements. map() does not change the original array.

What is the only way to create a new map object JavaScript?

Map, in the other hand, has only one way to create, by using its built-in constructor and new syntax. The constructor receives an array or iterable object whose elements are key-value pairs — aka arrays with 2 elements [key, value].

Can a map key have multiple values JavaScript?

A single key maps to a single value. So you must change the value if you want multiple: var myMap = new Map(); myMap.


1 Answers

With an extra internal object for reverse mapping. Best if we add a utility class ;) like the following:

ES6 syntax (scroll down for ES5 syntax)

class TwoWayMap {     constructor(map) {        this.map = map;        this.reverseMap = {};        for(const key in map) {           const value = map[key];           this.reverseMap[value] = key;           }     }     get(key) { return this.map[key]; }     revGet(key) { return this.reverseMap[key]; } } 

Then you instantiate like this:

const twoWayMap = new TwoWayMap({    '*' : '__asterisk__',      '%' : '__percent__',    .... }); 

Finally, to use it:

twoWayMap.get('*')   //Returns '__asterisk__' twoWayMap.revGet('__asterisk__')  //Returns '*' 

Bonus: If you also need set/unset methods, you can do it (inside the class) easily like:

set(key, value) { this.map[key] = value; } unset(key) { delete this.map[key] } // same for revSet and revUnset, just use this.reverseMap instead 

Equivalent with ES5 (old js) syntax:

function TwoWayMap(map) {    this.map = map;    this.reverseMap = {};    for(var key in map) {       var value = map[key];       this.reverseMap[value] = key;       } } TwoWayMap.prototype.get = function(key){ return this.map[key]; }; TwoWayMap.prototype.revGet = function(key){ return this.reverseMap[key]; }; 

Usage is the same:

var twoWayMap = new TwoWayMap({    '*' : '__asterisk__',      '%' : '__percent__',    .... }); twoWayMap.get('*')   //Returns '__asterisk__' twoWayMap.revGet('__asterisk__')  //Returns '*' 

Hope this helps. Cheers

like image 130
Edgar Villegas Alvarado Avatar answered Sep 24 '22 08:09

Edgar Villegas Alvarado