admin管理员组

文章数量:1242807

In JavaScript I want to store values to pound keys, similar to a C# dictionary with a tuple as key. This is where I came across the Map class. However, it does not seem to work quite as well as I would like it to. Here's my current approach:

var test = new Map();

test.set({a: 1, b: 1}, 'Bla');
test.set({a: 5, b: 7}, 'Blub');

test.get({a: 1, b: 1}); // ==> Returns undefined; would expect 'Bla'

I guess, that this has something to do that both objects with {a: 1, b: 1} have a different memory address and therefore are the same, but not identical. The Dictionary class in c# uses a hash function in background. Is there something similar in JS? Or a much easier approach?

My real key object consistst of three strings.

In JavaScript I want to store values to pound keys, similar to a C# dictionary with a tuple as key. This is where I came across the Map class. However, it does not seem to work quite as well as I would like it to. Here's my current approach:

var test = new Map();

test.set({a: 1, b: 1}, 'Bla');
test.set({a: 5, b: 7}, 'Blub');

test.get({a: 1, b: 1}); // ==> Returns undefined; would expect 'Bla'

I guess, that this has something to do that both objects with {a: 1, b: 1} have a different memory address and therefore are the same, but not identical. The Dictionary class in c# uses a hash function in background. Is there something similar in JS? Or a much easier approach?

My real key object consistst of three strings.

Share Improve this question edited Apr 15, 2020 at 14:36 André Reichelt asked Apr 15, 2020 at 14:32 André ReicheltAndré Reichelt 1,6311 gold badge22 silver badges59 bronze badges 5
  • Your analysis is right: Map uses reference equality on the keys and not value equality. If your objects just have three fixed strings, can you synthesize a key for map by bining them? E.g. makeKey = (({s1, s2, s3}) => `${s1}~${s2}~${s3}`? Then test.set(makeKey({a: 1, b: 1}), 'Bla') ... test.get(makeKey({a: 1, b: 1}) – Scott Sauyet Commented Apr 15, 2020 at 14:35
  • Sure, that would work. Would you rather use the Map class or a simple object in that case? – André Reichelt Commented Apr 15, 2020 at 14:37
  • 2 Either one would be fine. To my mind, this restriction on Map makes it much less useful than it could be. – Scott Sauyet Commented Apr 15, 2020 at 14:38
  • @ScottSauyet If you want, you can post your idea as an answer. – André Reichelt Commented Apr 15, 2020 at 14:53
  • 1 Nah, simple enough to be just a ment. Besides, the JSON.stringify ment from Captain Mhmdrz_A is most likely a better idea. – Scott Sauyet Commented Apr 15, 2020 at 15:29
Add a ment  | 

2 Answers 2

Reset to default 6

Your analysis is correct. It works like this because in Javascript you usually operate primitive objects that don't have all this hashing behavior attached to them out of the box. Nothing stops you from implementing your own Dictionary with hash function in background though

class Dictionary {
  map = {}

  constructor(hashFunction) {
    this.hashFunction = hashFunction
  }

  set(key, item) {
    this.map[this.hashFunction(key)] = item
  }

  get(key) {
    return this.map[this.hashFunction(key)]
  }

  delete(key) {
    delete this.map[this.hashFunction(key)]
  }
}

const dict = new Dictionary((keyObject) => JSON.stringify(keyObject))
dict.set({ a: 1, b: 2 }, 'hello')
console.log(dict.get({ a: 1, b: 2 })) // hello

As to what to use, Map or object, the difference between Map and object is simply that object only supports string keys (also Symbols but irrelevant right now) while Map supports any value at a cost of using more resources, less patibility with old browsers, and it's generally less handy to use than object (and also stops GC from cleaning out those objects you use as keys). That said, object is your choice here

{} this operator will create a new object every time; and a new object will have a different object refenece each time; if you save the object reference and use that for multiple operation its ok; but since you are trying to use a new object refence every time it won't work; you may either use a primitive type as key, or same object reference like the snippet below

//approach 1 using same object reference
var test = new Map();
var obj = {a: 1, b: 1};
test.set(obj, 'Bla');
test.set({a: 5, b: 7}, 'Blub');
let result = test.get(obj); 
console.log(result);

// aproach 2 using JSON.stringify
test = new Map();
test.set(JSON.stringify({a: 1, b: 1}), 'Bla');
test.set({a: 5, b: 7}, 'Blub');
result = test.get(JSON.stringify({a: 1, b: 1})); 
console.log(result)

本文标签: dictionaryJavascript map with composite keysStack Overflow