Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialchelseacheevers
13,786 PointsCombining Filter and Reduce - Video confusion
So, I took a break from this section yesterday bc it was becoming a lot. Today I was understanding the first few concepts, then arrived here and I am completely lost.
I suppose what I understand the least, is how in the example, it knew to compare the "highest" value. Same with the sum. If these are variables we are supplying, then how do they know what to do? I understand comparison operators are involved ('>', '+'), I guess I am just missing the link between how they are working here!
2 Answers
Juan Luna Ramirez
9,038 PointsFirst, reduce allows you to perform some logic for each item in the array with the goal of getting something at the end when it's finished going through each item. This something can be anything, a string, a number, an object, an array of strings, an array of objects, an array of arrays... you get it.
Let's look at the "highest" value example
We can say that the something we want in the end is an object that represents a product with the highest price. So this { name: 'paper towels', price: 6.99 }
next, the first argument to a reduce
function, commonly known as a callback function, is the logic that will be use to figure what that something will be at the end, in our case the product object with the highest price. The important part to note here, in regards to your question, is that you are not calling the callback function. You can think of it as the reduce
function calling the callback
function for you.
// if we were to declare the callback function on its own
function callback (highest, product) {
if (highest.price > product.price) {
return highest;
}
return product;
}
Basically reduce
is saying, "hey, I'm going to go through each item in this array for you and keep track of that something you want in the end... but I need you to tell me how to calculate that something... so, gimme a function I can call to calculate this something"
So you can actually use whatever names you want for the parameters of the callback
function. When the reduce
function calls it, the first argument will be how that something is coming along as reduce
iterates through each item. The value that is returned from the callback
function is used by reduce
as the first argument again for the next item and so on until there are not more items. The final return value is what you get at the end.
I would suggest looking for more examples online of how reduce works. You may understand someone else's explanation better than this one or the video. I'll post an explanation I wrote in another question which may help but don't feel pressured to understand this from a single explanation.
Juan Luna Ramirez
9,038 Pointsreduce
allows you to do some work for each item in an array. Then, you get something at the end of doing all that work for every item.
Maybe it would help to think about the output or the return value of running the reduce
function. Meaning, what do you want to have at the end of running the reduce
function? Is it a brand new array, a number, a string, or an object?
Turns out, you can get anything from the reduce
function which makes it very flexible but sometimes difficult to grasp, and I guess explain. OK?! O_o
Let's look at the arguments like you suggest. The reduce function takes 2 arguments:
- The function that will do the work for each item in the array. This is often referred to as the
callback
function or reducer function in case you want to research this some more. - The initial value before we even start looping over the array
so we can say the signature is array.reduce(callback, initialValue)
.
Initial Value
Let talk about the initial value first since I'm trying to explain this in terms of what you want to get at the end of running reduce
.
In practice, I almost always (probably always) use the same data type for the initial value as what I want at the end of running the reduce
function. What I mean is:
-
If I want to get a number at the end I'll use a number as the initial value.
8
is the initial valueconst numberOutput = [1, 2, 3].reduce(callback, 8)`
-
If I want to get an array at the end I'll use an array as the initial value.
[]
is the initial valueconst arrayOutput = ['hello', 'hi', 'sup'].reduce(callback, [])`
-
If I want an object at the end I'll use an array as the initial value.
{}
is the initial valueconst objectOutput = ['hello', 'hi', 'sup', 'hello'].reduce(callback, {})`
And so on!
This however does not guarantee that the end result will be that same data type as I'll try to show at the end. In fact, the initial value is optional and I would encourage you to research what happens if you don't have it. I don't want to complicate it here for you. I would just recommend using an initial value of the same data type as you want at the end, while you get more familiar with reduce
.
Callback Function
Now we'll look at the callback
function which allows us to do some work for each item in the array. There is some useful information we might need each time we do this work. These are the parameters of the callback
function.
- The first thing that would be useful to know is how our final output, the thing we want at the end of running the reduce function is looking thus far. This is often referred to as the
accumulator
- It is also often useful to know the item of the array we are currently on. This is often referred to as the
currentValue
There are 2 more argument but you can research this on your own to keep this simple here.
For simplicity, let's just say the signature is callback(accumulator, currentValue)
ACCUMULATOR
This is the thing we want to get at the end of running the reduce
function. So how do you control what this is during each item of the array? During the first item of the array, it will be the initial value we passed as the second argument to reduce
. After that, it's whatever we return from the previous callback
function.
Let's put it all together in an example: I'm going to add all the 1
s in the array to the initialValue 10
. So at the end of running reduce
I expect to get a number which should be 13
// I'm going to declare the callback function separately so you can,
// hopefully, clearly see the callback parameters and the reduce arguments.
// I just named the parameters "accumulator" and "currentValue" as they are often
// called but you can use whatever names makes sense to you.
const callback = (accumulator, currentValue) => {
// I'm going to add the current 1 which is saved to currentValue
// to the current accumulator.
const updatedNumber = accumulator + currentValue
// IMPORTANT part: now we are going to return the updatedNumber so that
// THIS updatedNumber will become the next accumulator when we run this function
// again for the next item in the array. The last time this run is our final
// output we are looking for.
return updatedNumber
}
const numberOutput = [1, 1, 1].reduce(callback, 10)
console.log(numberOutput) // 13
Here are the values of each iteration:
iteration | current array value | ACCUMULATOR |
---|---|---|
0 | 1 | 10 |
1 | 1 | 11 |
2 | 1 | 12 |
The return value of the last callback
function is the final result, the thing you wanted at the end of running the reduce
function, the number 13
. Phew!!
Another example. At the end I want an array with all the words in upppercase
// I'm going to put the callback function inline now, but it's all the same
const upcased = ['hi', 'hello', 'hola'].reduce((accumulator, currentValue) => {
// uppercase the current word
const wordInUpperCase = currentValue.toUpperCase()
// add the uppercased word to our acccumulator array
accumulator.push(wordInUpperCase)
// important: return the array that now has the newly added word so that
// it becomes the next accumulator array. The last time this is returned
// becomes the final output we are looking for.
return accumulator
}, [])
console.log(upcased) // ["HI", "HELLO", "HOLA"]
iteration | current array value | ACCUMULATOR |
---|---|---|
0 | 'hi' | [] |
1 | 'hello' | ["HI"] |
2 | 'hola' | ["HI", "HELLO"] |
The return value of the last callback
function will be ["HI", "HELLO", "HOLA"]
, our final output we were looking for.
Let me just show you one final and absolutely obsured example, just to point out that the last return value is our final output. I'm going to repeat the adding of number example but this time I'm going to sabotage the whole thing by returning a string at the very last iteration. Again, this is probably not something you would want to do but that you might actually accidentally do, creating a bug!
// I'm going to use the 3rd parameter which is the index so I know we're
// at the last item, where I'm going to sabotage this thing. Again, research
// the additional parameters.
const callback = (accumulator, currentValue, index) => {
const isLastIteration = index === 2
const updatedNumber = accumulator + currentValue
// it's the last iteration, do something crazy!
if (isLastIteration) {
return 'nope!!!'
}
return updatedNumber
}
const numberOutput = [1, 1, 1].reduce(callback, 10)
console.log(numberOutput) // "nope!!!"
Here are the values of each iteration:
iteration | current array value | ACCUMULATOR |
---|---|---|
0 | 1 | 10 |
1 | 1 | 11 |
2 | 1 | 12 |
Everything was working fine till the end because the return value of the last callback
function is just "nope!!". This will be the final result we get. lol!
Yeah, this is one is hard but try out some more example and console out the result to see if you can make it work. I would definitely recommend learning this method though, it's very powerful and useful. Search for other explanations. Hope this is somewhat helpful.
Juan Luna Ramirez
9,038 PointsJuan Luna Ramirez
9,038 PointsAlso,
filter
works in a similar way where you have to pass in acallback
function to determine whether to keep the item or not. The return value of thatcallback
function is boolean because you want to say true, keep it, or false don't keep it. Again, you are not calling the function, it is done internally by thefilter
function.Another thing, don't get thrown off by chaining array methods. Here is an example without chaining methods.
But it's more convenient to just chain them if you don't need to use the results of
productsUnder10
somewhere else in your code.