Как создать двустороннее сопоставление в JavaScript или какой-либо другой способ поменять значения?
В настоящее время у меня есть необходимость временно менять значения в строке JavaScript, и поэтому мне нужно иметь двунаправленную карту/хэш.
Например, скажем, я хочу изменить \*
на __asterisk__
(это просто пример, это не то, что я на самом деле пытаюсь сделать). Мне нужно будет сопоставить *
с __asterisk__
(чтобы поменять значение в исходной строке), но тогда мне также нужно будет отобразить __asterisk__
на *
(to вернуть исходную строку).
Вот какой-то быстрый псевдоиш-код того, что я ищу, чтобы вы могли понять его лучше:
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'
Это то, о чем я думал и пытался до сих пор:
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 } }
Очевидная проблема заключается в том, что способ получить по значению слишком сложный, и я не хочу, чтобы каждый раз записывать все это каждый раз, когда я должен искать обратный поиск.
Я просто хотел знать: есть ли способ решить эту проблему, не прибегая к переходу через объект? Если нет, есть ли способ сделать это проще или чище?
Ответы
Ответ 1
Используйте два объекта. Один объект содержит отображение * -> _asterisk_
, другой объект содержит _asterisk_ -> *
.
var forwardMap = {'*': '__asterisk__', '%': '__percent__', ...};
var reverseMap = {};
for (var key in forwardMap) {
if (forwardMap.hasOwnProperty(key)) {
reverseMap[forwardMap[key]] = key;
}
}
Ответ 2
С дополнительным внутренним объектом для обратного отображения. Лучше всего, если мы добавим служебный класс;) вот так:
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]; };
Затем вы создаете экземпляр как это:
var twoWayMap = new TwoWayMap({
'*' : '__asterisk__',
'%' : '__percent__',
....
});
Тогда для его использования:
twoWayMap.get('*') //Returns '__asterisk__'
twoWayMap.revGet('__asterisk__') //Returns '*'
РЕДАКТИРОВАТЬ: эквивалент с синтаксисом 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]; }
}
Использование такое же
Надеюсь это поможет. ура
Ответ 3
Мне нужно что-то подобное, и создал https://www.npmjs.com/package/bi-directional-map
Он реализует 2-стороннюю карту с использованием 2 es6 Map, хотя она не имеет большой функциональности, она протестирована и, поскольку она написана typescript
, поставляется с официальными типизациями.
Ответ 4
Я бы просто использовал простой объект:
var map = { '*': '__asterisk__', '__asterisk__': '*', .... }
Если вы не хотите писать все это, посмотрите на реализацию подчеркивания _.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 }
}, {})
})
использование:
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