I was working on this problem to create a function using a reduce method that will get the max number in an array.
The instructor's answer is:
const numbers = [1, 2, 3, 4, 4, 5, 1, 3, 4];
const max = getMax(numbers);
console.log(max);
function getMax(array) {
if (array.length === 0) return undefined;
return array.reduce((accumulator, current) => {
return (accumulator > current) ? accumulator : current
});
I tried something like this:
return array.reduce((accumulator, current) => {
if (accumulator < current)
console.log(accumulator, current);
return accumulator = current;
});
I added console.log (accumulator, current) because I wanted to see what's going on with my code. The log shows as follows:
1 2
2 3
3 4
4 5
1 3
3 4
4
Question 1. I'd like to know why my function didn't give the right output (it returned 4, not the correct output 5). Shouldn't "accumulator" stay 5 when it is assigned as 5 during the loop?
Question 2. Why do I need to return (or add return in front of) array in the function, when there is already a return below the if statement?
You didn't use { ... }
after your if
statement, so only the first line console.log(...)
is happening when the condition is met. The accumlator = current
line always happens for each iteration. You must use return
when using imperative style if
statement. However you can skip return
when using functional style expressions, ie (accumulator, current) => accumulator < current ? current : accumulator
which says "if accumulator is less than current, return current, else return accumulator".
Consider this decomposed program. When we see max
as an independent function, it helps us see precisely the type of function reduce
is expecting -
const max = (a = 0, b = 0) =>
a < b // if a is less than b
? b // return b
: a // otherwise return a
const getMax = (numbers = []) =>
numbers.length === 0 // if numbers.length is zero
? undefined // return undefined
: numbers.reduce(max) // otherwise return reduction
console.log(getMax([1, 2, 3, 4, 4, 5, 1, 3, 4]))
// 5
console.log(getMax([]))
// undefined
console.log(getMax())
// undefined
We can see reduce
is produces the following computation -
// given
[1, 2, 3, 4, 4, 5, 1, 3, 4]
// starting with the first two
r = max(1, 2)
// then the next number
r = max(r, 3)
// then the next number
r = max(r, 4)
// then the next number
r = max(r, 4)
Or without intermediate r = ...
-
max(max(max(max(max(max(max(max(1, 2), 3), 4), 4), 5), 1), 3), 4)
We could write getMax
without reduce
, if we wanted -
const max = (a = 0, b = 0) =>
a < b
? b
: a
const getMax = (numbers = []) =>
numbers.length === 0 // without any numbers,
? undefined // there can be no max.
: numbers.length === 1 // if we only have one,
? numbers[0] // we already know max.
: max(numbers[0], getMax(numbers.slice(1))) // else
console.log(getMax([1, 2, 3, 4, 4, 5, 1, 3, 4]))
// 5
console.log(getMax([]))
// undefined
console.log(getMax())
// undefined
Or maybe you haven't learned slice
yet. You can use an array index, i
, to step thru your array -
const max = (a = 0, b = 0) =>
a < b
? b
: a
const getMax = (numbers = [], i = 0) =>
numbers.length === 0 // without any numbers,
? undefined // there can be no max.
: i + 1 >= numbers.length // if the next i is not in bounds,
? numbers[i] // this is the last number
: max(numbers[i], getMax(numbers, i + 1)) // else
console.log(getMax([1, 2, 3, 4, 4, 5, 1, 3, 4]))
// 5
console.log(getMax([]))
// undefined
console.log(getMax())
// undefined
Destructuring assignment can be used as well -
const max = (a = 0, b = 0) =>
a < b
? b
: a
const getMax = ([ num, ...more ] = []) =>
more.length === 0
? num
: max(num, getMax(more))
console.log(getMax([1, 2, 3, 4, 4, 5, 1, 3, 4]))
// 5
console.log(getMax([]))
// undefined
console.log(getMax())
// undefined
This might show you how you can invent your own reduce
-
const max = (a = 0, b = 0) =>
a < b
? b
: a
const reduce = (f, a = [], i = 0) =>
a.length === 0 // without any numbers,
? undefined // there can be no reduction.
: i + 1 >= a.length // if the next i is not in bounds,
? a[i] // this is the last element
: f(a[i], reduce(f, a, i + 1)) // else
const getMax = (numbers = []) =>
reduce(max, numbers) // <-- our reduce!
console.log(getMax([1, 2, 3, 4, 4, 5, 1, 3, 4]))
// 5
console.log(getMax([]))
// undefined
console.log(getMax())
// undefined