1

Let say we have a map in JS as below.

const someMap = new Map();

someMap.set(["Jack", "Mathematics"], "Fee=₹120000");
someMap.set(["Alyne", "Science"], "Fee=₹90000");


// Going to be undefined because the lists are compared by ===
console.log(someMap.get(["Jack", "Mathematics"]));

This prevents us from checking for keys in a map dynamically because of === comparison. One way I can think of is to convert it to a string like "Jack, Mathematics" and then use it as a key. But this doesn't look perfect.

What is the best way to represent keys which are lists? By best way, I mean a way where we preserve the list structure of the key. Let say we are converting the list ["adog", "isananimal"] to a string "adog,isananimal" and there is another list ["adog,isananimal"] which converts to the same string "adog,isananimal" which would create a confusion while retrieving the values.

kaushalpranav
  • 1,725
  • 24
  • 39
  • 1
    What is not perfect about stringification in your case? Given the constraints that seems to fit perfectly, maybe JSON stringification would be better to avoid some collisions with "just-strings" – Kaiido Sep 17 '21 at 06:53
  • If the order of the elements within the list is not an issue, I'm afraid, there's no better way than turn into string (probably, with some non-printable character as a delimiter, e.g. \ud8ff) – Yevhen Horbunkov Sep 17 '21 at 06:55
  • maybe if we eventually get [tuples](https://github.com/tc39/proposal-record-tuple#equality) then you could do this a little more elegantly. – Nick Parsons Sep 17 '21 at 06:57
  • 3
    Please do try to avoid superlatively quantified questions (i.e. best way, fastest, etc..) as these tend to garner opinionated responses. – Drew Reese Sep 17 '21 at 06:59
  • By not using arrays as key... It should be map of maps with usage `map.get("Jack").get("Mathematics")` – Selvin Sep 17 '21 at 07:07
  • You may come up with all sorts of array comparison approaches, but I don't think either of those will let you keep the superior performance of `Map`. – Yevhen Horbunkov Sep 17 '21 at 07:58
  • Just because I asked for the *best way* doesn't mean that this is opinion-based. I showed what's a bad way of doing it (by converting it to a string) and this clearly says that I was looking for a good way to preserve the list structure, because using some kind of delimiter like `,` when converting to a string is going to be specific to a problem. And when we don't have `,` in the fields of the list, it's going to cause problems. What I want is a generic solution that doesn't depend on specific types of values to be present in the list. – kaushalpranav Sep 18 '21 at 03:18

1 Answers1

3

Stringification is still the most straightforward approach. If you don't like the implications of that, you can hide the implementation details in a custom class that extends Map:

class ArrayKeyedMap extends Map {
  get(array) {
    return super.get(this.#toKey(array));
  }
  
  set(array, value) {
    return super.set(this.#toKey(array), value);
  }
  
  has(array) {
    return super.has(this.#toKey(array));
  }
  
  delete(array) {
    return super.delete(this.#toKey(array));
  }
  
  #toKey(array) {
    return JSON.stringify(array);
  }
}

const someMap = new ArrayKeyedMap();

someMap.set(["Jack", "Mathematics"], "Fee=₹120000");
someMap.set(["Alyne", "Science"], "Fee=₹90000");

console.log(someMap.get(["Jack", "Mathematics"]));

If you want, you can take it further and override other Map functions like keys() and entries() as well using a custom #fromKey() function to map the strings back to arrays.

Robby Cornelissen
  • 91,784
  • 22
  • 134
  • 156
  • 1
    Aside from being slower than something, like `.join('\ufffd')`, `JSON.stringify()` is not quite reliable when it comes to _non-standard_ array items, i.e. `JSON.stringify(['a',,'b']` / `JSON.stringify('a', undefined, 'b'])` / `JSON.stringify(['a', null, 'b'])` will produce exactly the same output. Moreover, essentially, it is still the same solution that OP has already considered (when was asking for alternatives). – Yevhen Horbunkov Sep 17 '21 at 07:35
  • @YevgenGorbunkov Agreed on the problem with `JSON.stringify()`. The particular stringification function to use was not the focus of my answer, and I used `JSON.stringify()` because it's something that would fit most use cases. OP indicated that stringification was an option they considered, but that it didn't "look perfect". My answer provides a way to make it look cleaner by hiding away the stringification. A similar inheritance approach (or even a proxy) could be used to perform a deep equals comparison of the keys, but performance would likely be horrendous. – Robby Cornelissen Sep 17 '21 at 08:07