1

There are multiple questions here in SO that are similar to my question, but none really answers it completely.

Basically, I want to have objects as keys in JavaScript. I know it is possible with Map, however, it doesn't fully apply to my use-case. Here is the reason:

Let's say I have two objects, var d1 = {a: 1, b: 2} and var d2 = {a: 1, b: 2}, and a Map var m = new Map(). When adding d1 to m, when I call m.get(d2) I will get undefined. I assume it is because Map works in a reference-like manner.

However, I want the following functionality:

m.set(d1, 'hit');
m.get(d2) // should return 'hit' because properties and values of d1 = d2

One approach I thought of was not to use Map, but a simple JS object. Keys would be JSON.stringify(obj) and when I want to get a value from the object, I use JSON.parse(key) and then perform object equality check (Object.getOwnPropertyNames and then checking one-by-one).

However, I feel that this approach is way more complex and time-consuming than it should be. What I am looking for is probably a hash function of some sort that would efficiently map a object with keys of type String to values of type Number (integer in my case). Also, the ordering can be different (d1 = {a: 1, b: 2} should equal d2 = {b: 2, a: 1}).

How to design an efficient hash function to work with either JS Objects/Maps to perform the above-mentioned operations?

Dragos Strugar
  • 838
  • 1
  • 8
  • 25
  • Do the objects always have the same keys? – Barmar Sep 28 '19 at 13:25
  • 2
    If you use a hash function, you'll have to implement your own hash table, not use it as the key in a map, because there can be hash collisions. – Barmar Sep 28 '19 at 13:26
  • Objects do not have the same keys always. Some of them can include only 2 properties, some may have 30. And they can be different. – Dragos Strugar Sep 28 '19 at 13:53

1 Answers1

1

Write a function that turns the object into a string with the keys in a consistent order.

function objToKey(obj) {
  Object.keys(obj).sort().map(k => `${k}:${obj[k]}`).join(',');
}

var d1 = {a: 1, b: 2},
  d2 = {b: 2, a: 1},
  m = new Map();

m.set(objToKey(d1), "foo");
console.log(m.get(objToKey(d2)));
Barmar
  • 596,455
  • 48
  • 393
  • 495
  • Yeah, that is good, but keys could be anything in my case (a-z, A-Z, String(1)-String(9)) – Dragos Strugar Sep 28 '19 at 13:53
  • 1
    OK, I've generalized it to a function that sorts the keys and includes them in the result. – Barmar Sep 28 '19 at 13:58
  • Yeah that would work. The time complexity of such an approach is I would say pretty high. But that would work, yes. I will accept your answer. Do we need a `Map` in this case then? I would use just a normal Object, though. – Dragos Strugar Sep 28 '19 at 16:32
  • [Map vs Object](https://stackoverflow.com/questions/18541940/map-vs-object-in-javascript#targetText=You%20can%20get%20the%20size,that%20operates%20on%20individual%20elements.) – Barmar Sep 29 '19 at 03:13