Home > OS >  Counting instances of values in an object using Array.prototype.reduce()
Counting instances of values in an object using Array.prototype.reduce()

Time:01-25

Here's an MDN example of Array.prototype.reduce() I'm not quite understand:

const names = ["Alice", "Bob", "Tiff", "Bruce", "Alice"];

const countedNames = names.reduce((allNames, name) => {
    const currCount = allNames[name] ?? 0;
    return {
        ...allNames,
        [name]: currCount   1,
    };
}, {});

// countedNames is:
// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }

What do allNames[name] ?? 0 and ...allNames, mean here, and how does it generate the result? Thank you!

I searched the ... and ?? meaning, but still can't understand the use of allNames[name]? is this same with array[index]?

CodePudding user response:

const currCount = allNames[name] ?? 0

This is a use of the Nullish coalescing operator. It means that the variable currCount will first try to be assigned the value of allNames[name]. However, if that results in a "nullish" value (in this case undefined because there hasn't been anything assigned in allNames for a specific name), then the variable gets assigned to 0.

return {
...allNames,
};

This is a use of the spread operator and object destructuring. It means that the a new object will be created with all the properties (keys and values) of the old allNames object.

[name]: currCount   1,

This part says to create a new property with the key as a specific name and the value as the current count plus one. Combined with the snippet above, this will create a new object that's the same as allNames, except that the property with the key name will get overwritten, with the new value having an updated count.

CodePudding user response:

Your .reduce() function "reduces" (converts) the input Array into an Object {}
Since the object has no properties (it's "empty") you cannot increment a value to a non-existing property-value.

In the first iteration allNames[name] is undefined.

const currCount = allNames[name] ?? 0;

You cannot later increment undefined therefore the Nullish coalescing operator ?? makes sure to fallback that undefined the value to 0 - and stores it into currCount.

  return {
    ...allNames,
    [name]: currCount   1,
  };

The above just uselessly destructures the ...allNames object into a new Object (that is then returned and reused in the next iteration as a modified allNames) - and overrides the number of a specific property Name.

Here's a different (better, more legible) remake of the same:

const names = ["Alice", "Bob", "Tiff", "Bruce", "Alice"];

const countedNames = names.reduce((ob, name) => {
  ob[name] ??= 0; // if undefined, set that property and set value of 0
  ob[name]  = 1;  // Increment value by 1
  return ob;
}, {});

console.log(countedNames)

Which without using any fancy code is the same as doing:

const names = ["Alice", "Bob", "Tiff", "Bruce", "Alice"];

const countedNames = names.reduce((ob, name) => {
  if (!ob.hasOwnProperty(name)) {
    ob[name] = 0;
  }
  ob[name]  = 1; // Increment it
  return ob;
}, {});

console.log(countedNames)

which, without the .reduce() it's done like:

const names = ["Alice", "Bob", "Tiff", "Bruce", "Alice"];

const ob = {};
names.forEach((name) => {
  if (!ob.hasOwnProperty(name)) {
    ob[name] = 0;
  }
  ob[name]  = 1; // Increment it
});

console.log(ob)

  • Related