Javascript reduce initialValue is empty object, what's the meaning of it?

Viewed 1352

In MDN Array.prototype.reduce() , what's the meaning of allNames[name]? allNames should be {} first, but if object is empty, allNames[name] = 1 equal to {}['Alice'] = 1 ? how can it become { 'Alice': 1}, I'm so confused.

Counting instances of values in an object

var names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];

var countedNames = names.reduce(function (allNames, name) { 
  if (name in allNames) {
    allNames[name]++;
  }
  else {
    allNames[name] = 1;
  }
  return allNames;
}, {});
// countedNames is:
// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }
3 Answers

Array#reduce is an aggregation or accumulator function. This means it takes a collection of items (names) and boils it down to a single "accumulated" value (allNames).

names.reduce(function (allNames, name) {  // `allNames` is the accumulated value, `name` is the current item in `names`
  if (name in allNames) {
    allNames[name]++;
  }
  else {
    allNames[name] = 1;
  }
  return allNames;
}, {}); // The empty object here is the initial value of the accumulated value

So this function creates an accumulated value that is an object with a key corresponding to each name in names, and values corresponding to the frequency of that name in names.

Finally: note that objects have an index notation for property access/creation (very similar to arrays!). So the following means "if such a property does not already exist on object allNames, create a property with a name that is the value of variable name, and assign the value 1 to its value:

allNames[name] = 1

From the docs you provided:

The reducer function takes four arguments: Accumulator (acc) Current Value (cur) Current Index (idx) Source Array (src)

So the first variable is the accumulator, a variable that will hold accumulated values that you eventually will calculate, like in this example you are accumulating names.

The reduce function above can be rewritten into the following function.

This streamlined version shows that we are modifying the result (starts with {}) by incrementing the value for the name.

If result[item] is undefined, we use zero.

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

const frequencyMap = (items) => items.reduce((result, item) =>
  ({ ...result, [item]: (result[item] || 0) + 1 }), {});

console.log(frequencyMap(names));
.as-console-wrapper { top: 0; max-height: 100% !important; }

Here is the really-long version without reduce.

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

const frequencyMap = {};
for (let i = 0; i < names.length; i++) {
  const name = names[i],
        prev = frequencyMap[name];
  if (prev !== undefined) {
    frequencyMap[name] += 1; // Increment value by 1
  } else {
    frequencyMap[name] = 1;  // Initial value
  }
}

console.log(frequencyMap);
.as-console-wrapper { top: 0; max-height: 100% !important; }

Related