For Typescript users , the answers of others (especially czerny ) can be generalized into a good type-safe and reusable base class:
abstract class StringifyingMap<K, V> { private map = new Map<string, V>(); private keyMap = new Map<string, K>(); has(key: K): boolean { let keyString = this.stringifyKey(key); return this.map.has(keyString); } get(key: K): V { let keyString = this.stringifyKey(key); return this.map.get(keyString); } set(key: K, value: V): StringifyingMap<K, V> { let keyString = this.stringifyKey(key); this.map.set(keyString, value); this.keyMap.set(keyString, key); return this; } /** * Puts new key/value if key is absent. * @param key key * @param defaultValue default value factory */ putIfAbsent(key: K, defaultValue: () => V): boolean { if (!this.has(key)) { let value = defaultValue(); this.set(key, value); return true; } return false; } keys(): IterableIterator<K> { return this.keyMap.values(); } keyList(): K[] { return [...this.keys()]; } delete(key: K): boolean { let keyString = this.stringifyKey(key); let flag = this.map.delete(keyString); this.keyMap.delete(keyString); return flag; } clear(): void { this.map.clear(); this.keyMap.clear(); } size(): number { return this.map.size; } protected abstract stringifyKey(key: K): string; }
In this case, the implementation of the example will be so simple: just override the stringifyKey method. In my case, I am making the uri string property.
class MyMap extends StringifyingMap<MyKey, MyValue> { protected stringifyKey(key: MyKey): string { return key.uri.toString(); } }
An example of use then is as if it were a regular Map<K, V> .
const key1 = new MyKey(1); const value1 = new MyValue(1); const value2 = new MyValue(2); const myMap = new MyMap(); myMap.set(key1, value1); myMap.set(key1, value2);
Jan Dolejsi Jul 6 '19 at 9:21 2019-07-06 09:21
source share