2

I have a use case where I want to get an item from a Map. If that item doesn’t exist, I want to insert an initial value and save it for later. I also would like to use const variables so that I can’t accidentally rebind the local. I know I can write my own helper, but it seems to me that this pattern requires a lot of writing for a pattern which I expect to be quite common:

const item = myMap.has(key) ? myMap.get(key) : myMap.set(key, initialize()).get(key);

or to avoid the .get() immediately after the .set():

const item = myMap.has(key) ? myMap.get(key) : (() => {const value = initialize(); myMap.set(key, value); return value})();

Is there a simpler way to get an item from a Map into a const variable and, if it doesn’t yet exist, insert an initial value for the key first?

I know that a similar question exists, but in that question there is no requirement that the inserted item be stored in a local after insertion and it uses let rather than const.

EDIT: I’ve gone with the utility function route and created maputil.

binki
  • 7,754
  • 5
  • 64
  • 110

1 Answers1

2

We can reduce it ever so slightly, factoring out the .get(key) part:

const item = (myMap.has(key) ? myMap : myMap.set(key, initialize())).get(key);

...but I don't think we can go further without introducing a new function.

const initialize = _ => 42;
const myMap = new Map();
const key = "answer";
const item = (myMap.has(key) ? myMap : myMap.set(key, initialize())).get(key);
console.log(item);
console.log(Array.from(myMap.keys()));

So yeah, probably a candidate for a utility function. :-)

Standalone:

const getOrAdd = (map, key, initializer) => {
  if (map.has(key)) {
    return map.get(key);
  }
  const value = initializer();
  map.set(key, value);
  return value;
};
const initialize = _ => 42;
const myMap = new Map();
const key = "answer";
const item = getOrAdd(myMap, key, initialize);
console.log(item);
console.log(Array.from(myMap.keys()));

...or if you can extend builtins in your project (it's okay for some projects, not for others):

Object.defineProperty(Map.prototype, "getOrAdd", {
  value: function(key, initializer) {
    if (this.has(key)) {
      return this.get(key);
    }
    const value = initializer();
    this.set(key, value);
    return value;
  }
});
const initialize = _ => 42;
const myMap = new Map();
const key = "answer";
const item = myMap.getOrAdd(key, initialize);
console.log(item);
console.log(Array.from(myMap.keys()));
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875