Exact Change - my real horror

Hello, campers! My name is Sergey, I am from Russia. Sorry for my bad English.

I chose that category becase my problem actually not in JS. I can undestaund many things in JS, but that challenge is really hard for me. I don`t understand Beginner Code Solution… Yeah, it is bad.

I look at that part of code

`````` var register = cid.reduce(function(acc, curr) {
acc.total += curr[1];
acc[curr[0]] = curr[1];
return acc;
}, {total: 0});
``````

and i don`t understand it in general. Why “.total”? Is it a metod of object?

So `cid` is an array that looks like this:

``````[["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.10], ["QUARTER", 4.25], ["ONE", 90.00], ["FIVE", 55.00], ["TEN", 20.00], ["TWENTY", 60.00], ["ONE HUNDRED", 100.00]]
``````

So it’s an array of arrays.

`reduce` takes an array, and recombines the data in the array into something else. That something else is specified by an accumulator. `reduce` goes through the array, and for every element, runs a function that combines that element with the accumulator.

Here is an explanation of reduce I wrote that might be useful:

In the code you posted, the accumulator is an object that looks like `{total: Number}` - an object that starts out with a single key `total`. What the code is doing is going through the `cid` array, one-by-one, and:

1. Adding the value in the array to the value for `total`.
2. Adding a new key/value to the accumulator matching the current `cid` value - so like after the first value, the accumulator will look like: `{DIME: 3.10, total: 3.1}`.

It might make more sense if I rewrite it as a loop. I’ll use `accumulator` instead of `acc`, and `cashInDrawer` rather than `cid`.

``````var accumulator = {total: 0};
var cashInDrawer = [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.10], ["QUARTER", 4.25], ["ONE", 90.00], ["FIVE", 55.00], ["TEN", 20.00], ["TWENTY", 60.00], ["ONE HUNDRED", 100.00]];

for (var i = 0; i < cashInDrawer.length; i++) {
// Add the cash value to the `total` in `accumulator`.
// The cash value is the second element (index 1) in each sub-array:
accumulator.total += cashInDrawer[i][1];
// Set a property on the object:
accumulator[cashInDrawer[i][0]] = cashInDrawer[i][1];
}
``````

It’s more obvious if I use destructuring:

``````for (let i = 0; i < cashInDrawer.length; i++) {
let [denomination, value] = cashInDrawer[i];
// Add the cash value to the `total` in `accumulator`.
// The cash value is the second element (index 1) in each sub-array:
accumulator.total += value;
// Set a property on the object:
accumulator[denomination] = value;
}
``````

This results in `accumulator` ending up as:

``````{
total: 335.41,
PENNY: 1.01,
NICKEL: 2.05,
DIME: 3.1,
QUARTER: 4.25,
ONE: 90,
FIVE: 55,
TEN: 20,
TWENTY: 60,
'ONE HUNDRED': 100
}
``````
3 Likes

Thanks!
I decide to take a rest and learn some js books, before I go to next challenge.

Thank you so much for the super clear explanation.
I still have one more question regarding the `reduce` method.
I thought `reduce` method would only return one single value. Is this the case only when you do math?
Otherwise, it would behave like for loop that can also make a list ? like this code here?
`acc[curr[0]] = curr[1]` in reduce above?

`reduce` just [recursively] combines a data structure into a new value: that value can be anything.

So for example, reimplementing some of the JS array methods (and adding some other common ones):

The normal example, using it to take an array of numbers and sum them, returning a single value: `sum([1,2,3,4])` returns `10`

``````function sum(arr) {
return reduce((a,b) => a + b, 0);
}
``````

`reverse` returns a reversed version of the input array (non-mutating version of `Array.prototype.reverse`). So `reverse([1,2,3,4])` returns `[4,3,2,1]`.

``````function reverse(arr) {
return arr.reduce((acc, v) => [v, ... acc], []);
}
``````

Do the same as `Array.prototype.map` - so `map([1,2,3,4], (x) => x ** 2)` returns `[1,4,9,16]`.

``````function map(arr, fn) {
return arr.reduce((acc, v) => {
return  acc.concat(fn(v));
}, []);
}
``````

Flattens an array of arrays to a single array, same as `Array.prototype.flat` - so `flatten([[1],[2],[3],[4]])` returns `[1,2,3,4]`.

``````function flatten(arr) {
return reduce((acc, arr) => [...acc, ...arr], [])
}
``````

That only works for one level of nesting, so could take an array of arrays of any depth and flatten to one array: so `flattenDeep([1,[2,[3,4]]])` returns `[1,2,3,4]`.

``````function flattenDeep(arr) {
return arr.reduce((acc, v) => {
if (Array.isArray(v)) {
return acc.concat(flatten(v));
} else {
return acc.concat(v);
}
}, []);
}
``````

Joins an array into a string with a given joining string - same as `Array.prototype.join`, so `join([1,2,3,4], ' ')` returns `'1 2 3 4'`.

``````function join(arr, joiner = ',') {
return arr.reduce((acc, v, index) => {
if (index == 0) {
return `\${v}`
} else {
return `\${acc}\${joiner}\${v}`;
}
}, '');
}
``````

Given an array, returns an array with an item inserted between each of the original values, so `intersperse([1,2,3,4], 'hi')` returns`[1, 'hi', 2, 'hi', 3, 'hi', 4]`.

``````function intersperse(arr, item) {
return arr.reduce((acc, v, index) => {
if (index == 0) {
return [v]
} else {
return acc.concat([item, v]);
}
}, []);
}
``````

Filter and map on the same array, first function you pass is the filter, then anything that gets through that gets mapped - so `filterMap([1,2,3,4], (x) => x % 2 === 0, (x) => x ** 2)` returns `[4, 16]`

``````function filterMap(arr, filter, mapper) {
return arr.reduce((acc, v) => {
if (filter(v)) {
return  acc.concat(mapper(v));
} else {
return acc;
}
}, []);
}
``````
1 Like

Thank you so much. I will take a good read of this!