如何在JavaScript中创建双向映射,或者以其他方式交换值?

Doo*_*nob 19 javascript map data-structures

我目前需要暂时替换JavaScript字符串中的值,因此我需要有一个双向map/hash事物.

例如,假设我想改变\*__asterisk__(这只是一个例子,这不是我真正想要做).我必须能够映射*__asterisk__(换出原始字符串中的值),但是我还必须能够映射__asterisk__*(以获取原始字符串).

这里有一些我正在寻找的那种快速伪代码,所以你可以更好地理解它:

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'
Run Code Online (Sandbox Code Playgroud)

这是我迄今为止所考虑和尝试的内容:

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 } }
Run Code Online (Sandbox Code Playgroud)

这个问题的一个明显问题是,获取价值的方式过于复杂,而且我不想在每次反向查找时都写出整个事情.

我只想知道:有没有办法解决这个问题,而不需要通过循环对象?如果没有,有没有办法让它更容易或更清洁?

Edg*_*ado 31

使用额外的内部对象进行反向映射.如果我们添加一个实用程序类,最好;)像这样:

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]; };
Run Code Online (Sandbox Code Playgroud)

然后你实例化如下:

var twoWayMap = new TwoWayMap({
   '*' : '__asterisk__', 
    '%' : '__percent__',
   ....
});
Run Code Online (Sandbox Code Playgroud)

然后,使用它:

twoWayMap.get('*')   //Returns '__asterisk__'
twoWayMap.revGet('__asterisk__')  //Returns '*'
Run Code Online (Sandbox Code Playgroud)

编辑:与ES6语法等效

class TwoWayMap {
    constructor(map) {
       this.map = map;
       this.reverseMap = {};
       for(let key in map) {
          const value = map[key];
          this.reverseMap[value] = key;   
       }
    }
    get(key) { return this.map[key]; }
    revGet(key) { return this.reverseMap[key]; }
}
Run Code Online (Sandbox Code Playgroud)

用法是一样的

希望这可以帮助.干杯

  • 这应该是公认的答案。埃德加,你介意更新它并添加一个 ES6 语法代码吗? (2认同)

Bar*_*mar 9

使用两个对象.一个对象包含* -> _asterisk_映射,另一个对象包含_asterisk_ -> *.

var forwardMap = {'*': '__asterisk__', '%': '__percent__', ...};
var reverseMap = {};
for (var key in forwardMap) {
    if (forwardMap.hasOwnProperty(key)) {
        reverseMap[forwardMap[key]] = key;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 那么我将不得不手动将每个键/值对反向复制到另一个对象?-_- (2认同)

spa*_*row 6

我只是使用一个普通的对象:

var map = { '*': '__asterisk__', '__asterisk__': '*', .... }
Run Code Online (Sandbox Code Playgroud)

如果您不想将所有这些都写出来,请在此处查看下划线的实现_.invert(object)


小智 5

有些人可能更喜欢更简洁的功能风格......

const create2WayMap = (seedMap, mapName, reversemapName) => ({
  [mapName]: { ...seedMap },
  [reversemapName]: Object.keys(seedMap).reduce((map, key) => {
    const value = seedMap[key]
    return { ...map, [value]: key }
  }, {})
})
Run Code Online (Sandbox Code Playgroud)

用法:

const myIDMap = create2WayMap(
  {
    1: 'SomeString',
    2: 'Another String',
    3: 'Another'
  },
  'idStrings',
  'idNumbers'
)

let id = 2
const str = myIDMap.idStrings[id] // yields 'Another String'
id = myIDMap.idNumbers[str] // yields 2
Run Code Online (Sandbox Code Playgroud)