Test case details

Preparation Code

<script src="https://cdn.jsdelivr.net/npm/dequal@2.0.3/dist/index.min.js"></script> <script src="https://unpkg.com/equivalent-key-map/dist/equivalent-key-map.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/immutable@4.3.7/dist/immutable.min.js"></script>
class DeepMapC { map = new Map(); constructor(equals = dequal.dequal) { this.equals = equals; } findKey(key) { for (let k of this.map.keys()) { if (this.equals(k, key)) return k; } } set(key, value) { this.map.set(this.findKey(key) ?? key, value); return this; } get(key) { const existingKey = this.findKey(key); if (existingKey) return this.map.get(existingKey); } has(key) { return !!this.findKey(key); } delete(key) { const existingKey = this.findKey(key); if (existingKey) return this.map.delete(existingKey); else return false; } clear() { this.map.clear(); } get size() { return this.map.size; } keys() { return this.map.keys(); } values() { return this.map.values(); } entries() { return this.map.entries(); } [Symbol.iterator]() { return this.map[Symbol.iterator](); } } class DeepMapS { map = new Map(); keyMap = new Map(); constructor(serialize, initialValues) { this.serialize = serialize; if (initialValues) { for (const [key, value] of initialValues) this.set(key, value); } } set(key, value) { const keyStr = this.serialize(key); this.keyMap.set(keyStr, key); this.map.set(keyStr, value); return this; } get(key) { return this.map.get(this.serialize(key)); } has(key) { return this.keyMap.has(this.serialize(key)); } delete(key) { const keyStr = this.serialize(key); this.keyMap.delete(keyStr); return this.map.delete(keyStr); } clear() { this.map.clear(); this.keyMap.clear(); } get size() { return this.map.size; } keys() { return this.keyMap.values(); } values() { return this.map.values(); } forEach(cb, thisArg) { this.keyMap.forEach((key, keyStr) => cb.call(thisArg, this.map.get(keyStr), key, this)); } copy() { const newMap = new DeepMap(this.serialize); // directly copying the map and keymap (instead of passing it to the constructor), avoids having to recalculate each key hash newMap.map = new Map(this.map); newMap.keyMap = new Map(this.keyMap); return newMap; } *entries() { for (let [keyStr, key] of this.keyMap.entries()) { yield [key, this.map.get(keyStr)]; } } [Symbol.iterator]() { return this.entries(); } } class DeepMapO { map = {}; keyMap = {}; constructor(serialize, initialValues) { this.serialize = serialize; if (initialValues?.[Symbol.iterator]) { for (const [key, value] of initialValues) this.set(key, value); } } set(key, value) { const keyStr = this.serialize(key); this.keyMap[keyStr] = key; this.map[keyStr] = value; return this; } get(key) { return this.map[this.serialize(key)]; } has(key) { return !!this.map[this.serialize(key)]; } delete(key) { const keyStr = this.serialize(key); const hasKey = !!this.map[keyStr]; delete this.keyMap[hasKey]; delete this.map[keyStr]; return hasKey; } clear() { this.map = {}; this.keyMap = {}; } get size() { return Object.keys(this.map).length; } *keys() { for (let keyStr in this.keyMap) yield this.keyMap[keyStr]; } *values() { for (let keyStr in this.keyMap) yield this.map[keyStr]; } *entries() { for (let keyStr in this.keyMap) yield [this.keyMap[keyStr], this.map[keyStr]]; } forEach(cb, thisArg) { for (let keyStr in this.keyMap) cb.call(thisArg, this.map[keyStr], this.keyMap[keyStr], this); } copy() { const newMap = new DeepMapO(this.serialize); // directly copying the map and keymap (instead of passing it to the constructor), avoids having to recalculate each key hash newMap.map = { ...this.map }; newMap.keyMap = { ...this.keyMap }; return newMap; } [Symbol.iterator]() { return this.entries(); } } const serialize = k => `${k.chain}}_{${k.joint}`; const deSerialize = str => { const parts = str.split('}_{'); return { chain: parts[0], joint: parts[1] }; }; const map = new Map(); const obj = {}; const mapIsEqual = new DeepMapC(dequal.dequal); const deepMapMap = new DeepMapS(serialize); const deepMapObj = new DeepMapO(serialize); const equivalentKeyMap = new EquivalentKeyMap(); let immutableMap = new Immutable.Map(); for (let chain = 0; chain < 5; chain++) { for (let joint = 0; joint < 10; joint++) { const key = { chain: `cf221f55-957c-43bf-be45-f5be6d2cebe4-${chain}`, joint: `dc7d8abf-871c-4980-84ed-c7049a67558d-${joint}` }; const value = `value-${chain}-${joint}`; map.set(serialize(key), value); obj[serialize(key)] = value; equivalentKeyMap.set(key, value); immutableMap = immutableMap.set(Immutable.fromJS(key), value); mapIsEqual.set(key, value); deepMapMap.set(key, value); deepMapObj.set(key, value); } } const testKey = { chain: `cf221f55-957c-43bf-be45-f5be6d2cebe4-${4}`, joint: `dc7d8abf-871c-4980-84ed-c7049a67558d-${8}` };

Test cases

Test #1

return map.get(serialize(testKey))

Test #2

return obj[serialize(testKey)]

Test #3

return equivalentKeyMap.get(testKey)

Test #4

return immutableMap.get(Immutable.fromJS(testKey))

Test #5

return mapIsEqual.get(testKey)

Test #6

return deepMapMap.get(testKey)

Test #7

return deepMapObj.get(testKey)