Mike Williamson Mike Williamson - 7 months ago 6
Javascript Question

How can I make Javascript's reduce method work on arrays of arrays?

Orig Problem



I was working on an exercise that should sum up the amount of change left in a cash register, variable
cid
.

cid
looks something like this:

var cid = [["PENNY", 0], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]];


In a case like this, when all of the values are 0, then I should report that the register is empty.

I thought something like this should work:

if (cid.reduce(function(prevVal, curVal) {
return prevVal[1] + curVal[1];
}) === 0)


But it didn't.




Digging In



Some strange things seem to happen when working with arrays within arrays and the
reduce
method. For instance:

cid.reduce(function(prevVal, curVal) {
return prevVal[1] + curVal[1];
});

NaN


Whereas, if I just let the entire array through, I do get something, albeit something strange:

cid.reduce(function(prevVal, curVal) {
return prevVal + curVal;
});

"PENNY,0NICKEL,0DIME,0QUARTER,0ONE,0FIVE,0TEN,0TWENTY,0ONE HUNDRED,0"





It's clear to me that, when using
reduce
, it isn't simply delving one level deeper into the array / object, as I had suspected it would.

However, the only other thing I might have suspected is also wrong: it's not delving into all the levels, either. If this were the case, I would have expected to have seen something like this (notice there are no commas):

"PENNY0NICKEL0DIME0QUARTER0ONE0FIVE0TEN0TWENTY0ONE HUNDRED0"





Two Questions




  1. Is there any way to effectively use the
    reduce
    method with multi-dimensional arrays like this?

  2. Can anyone help me understand what is going on under the hood here?


Answer

You're slightly misunderstanding the nature of reduce; the value in prevVal is not whatever value we were called with last; it's whatever value we returned last. Since you are returning an integer, prevVal is an integer, and prevVal[1] is undefined.

I'd suggest you alter your call to reduce to provide an explicit default of 0, and rewrite your function to assume that prevVal is always going to be a number, not a value in your array.

var cid = [
  ["PENNY", 0],
  ["NICKEL", 0],
  ["DIME", 0],
  ["QUARTER", 0],
  ["ONE", 0],
  ["FIVE", 0],
  ["TEN", 0],
  ["TWENTY", 0],
  ["ONE HUNDRED", 0]
]

var val = cid.reduce(function(prevVal, curVal) {
  return prevVal + curVal[1];
}, 0);

document.write("<pre>" + JSON.stringify(val) + '</pre>');

Comments