Please help me understand this reduce() example 🙏🏻

Hey there :wave:t2:

As I was going through some examples of how reduce() works.
I almost got it right, but I got stuck when trying to check whether properties existed or not (right after the first comment).

const inventory = [
  { type: "shirt", price: 4000 },
  { type: "pants", price: 4532 },
  { type: "socks", price: 234 },
  { type: "shirt", price: 2343 },
  { type: "pants", price: 2343 },
  { type: "socks", price: 542 },
  { type: "pants", price: 123 },
];

function inventoryReducer(totals, item) {
  // increment the type by 1
  totals[item.type] = totals[item.type] + 1 || 1;
  console.log(item);
  // return the totals, so the next loop can use it
  return totals;
}

const inventoryCounts = inventory.reduce(inventoryReducer, {});

console.log(inventoryCounts);

Why does this work?

totals[item.type]

But not this?

totals[item][type]

It has do with what this line of code does:
totals[item.type] = totals[item.type] + 1 || 1;

Basically what you are doing is taking the (in the beginning empty) object "totals"and you are giving it key-value pairs.
So the left part is the key and the right part is the value.

Both totals[item.type] as well as totals[item['type']] will work, because in both cases item.type or item['type'] is a string.

Here: totals[item][type] the issue is, that you are using type without quotation marks, as if it’s a variable, but you never assigned any value to it, hence it’s undefined.
You don’t need quotation marks when accessing a specific key in an object with dot notation, you do need them, when you are using bracket notation.

And here: totals[item]['type'] it is as if you are trying to access a key within the totals object, which doesn’t exist, because the object doesn’t have the ‘type’ key.

In the first iteration, item is { type: "shirt", price: 4000 }, so item.type is "shirt". This also means the reference totals[item.type] (total["shirts"] will be undefined since totals starts as an empty object with no properties. If you try to add 1 to undefined, this evaluates to NaN which is “falsy”. The || operator between two operands will cause the operand that is “truthy” (the 1 on the right side) to be assigned to totals[item.type] (currently totals["shirt"]. This means after this iteration of the reducer, totals looks like { shirt: 1 }.

In the second iteration, item is { type: "pants", price: 4532 }, so item.type is "pants". This also means the reference totals[item.type] (total["pants"] will be undefined since totals starts as an empty object with no properties. If you try to add 1 to undefined, this evaluates to NaN which is “falsy”. The || operator between two operands will cause the operand that is “truthy” (the 1 on the right side) to be assigned to totals[item.type] (currently totals["pants"]. This means after this iteration of the reducer, totals looks like { shirt: 1 , pants: 1 }.

In the third iteration, item is { type: "socks", price: 234 }, so item.type is "socks". This also means the reference totals[item.type] (total["socks"] will be undefined since totals starts as an empty object with no properties. If you try to add 1 to undefined, this evaluates to NaN which is “falsy”. The || operator between two operands will cause the operand that is “truthy” (the 1 on the right side) to be assigned to totals[item.type] (currently totals["socks"]. This means after this iteration of the reducer, totals looks like { shirt: 1 , pants: 1, socks: 1 }.

In the fourth iteration, item is { type: "shirt", price: 2343 }, so item.type is "shirt". This also means the reference totals[item.type] (total["shirts"] will be 2 since totals["shirt"] was already 1 from the previous iteration and adding 1 to 1 is 2. The || operator between two operands will cause the operand that is “truthy” (the 2 on the left side) to be assigned to totals[item.type] (currently totals["shirt"]. This means after this iteration of the reducer, totals looks like { shirt: 2 , pants: 1, socks: 1 }.

In the fifth iteration, item is { type: "pants", price: 2343 }, so item.type is "pants". This also means the reference totals[item.type] (total["pants"] will be 2 since totals["pants"] was already 1 from the previous iteration and adding 1 to 1 is 2. The || operator between two operands will cause the operand that is “truthy” (the 2 on the left side) to be assigned to totals[item.type] (currently totals["pants"]. This means after this iteration of the reducer, totals looks like { shirt: 2 , pants: 2, socks: 1 }.

In the sixth iteration, item is { type: "socks", price: 542 }, so item.type is "socks". This also means the reference totals[item.type] (total["socks"] will be 2 since totals["socks"] was already 1 from the previous iteration and adding 1 to 1 is 2. The || operator between two operands will cause the operand that is “truthy” (the 2 on the left side) to be assigned to totals[item.type] (currently totals["socks"]. This means after this iteration of the reducer, totals looks like { shirt: 2 , pants: 2, socks: 2 }.

In the final iteration, item is { type: "pants", price: 123 }, so item.type is "pants". This also means the reference totals[item.type] (total["socks"] will be 3 since totals["pants"] was already 2 from the previous iteration and adding 1 to 2 is 3. The || operator between two operands will cause the operand that is “truthy” (the 3 on the left side) to be assigned to totals[item.type] (currently totals["pants"]. This means after this iteration of the reducer, totals looks like { shirt: 2 , pants: 3, socks: 2 }.

1 Like

Thank you Michael, I get it now :pray:t2:
Don’t know why I was looking at those {} as anything but an empty object :sweat_smile:

Thanks you Randell, very concise explanation.

Weirdly enough I was stuck on wondering how adding {} + next current item would work…
Definitely not how I should have approached it. :smiley:

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.