Functional Programming in Kotlin (Part 2) — Map & Reduce
Today we’re gonna learn about something new and awesome called map.
Map
In the last article we learned about higher-order functions. We also learned to use a higher-order function Filter. Just like filter, map is another higher-order function. Also, like filter, it goes through an array, but unlike filter it doesn’t throw the objects away instead it transforms them.
What?! What does it mean?
Let me show you. Take a look at this array
This time we want to get an array of all the names of all the animals. this is super simple to solve with the map but before I do that I want to show you how we would solve this using a for loop.
var names = arrayListOf<String>()
for (animal in animals) {
names.add(animal.name)
}
The code is super straightforward it just loops the animals array and for each Animal, it just picks the name property and its pushes it into the names array.
Now, let’s do the exact same thing, but using a map instead. Let’s do this
var names = animals.map(fun(animal: Animals): String {
return animal.name
})
Remember that I told you that map is a function on the array object. Just like filter, map will take a callback function. The callback function will be passed each item in the animals array. But here is where map gets different from filter… filter expect that it’s callback function to return a true or false value that determine whether or not the item should be included in the array or not.
Map will include all items in the array but instead it expects the callback function to return a transformed object that it will put into the new array instead of the the original animal in this case that will be the name.
Using map to return a subset of an object like this where we return just the name property is a very common usage pattern, however since map just expects the callback to return any object we can use it to create completely new objects like below code example.
var names = animals.map(fun(animal: Animals): String {
return animal.name + "is a" + animal.species
})
Reduce
Before we talk about reduce. Let’s recap what we have learned so far. We’ve learned about a couple of higher-order functions map, filter and filterNot. what all these have in common is that they transform a list into something else.
Map take an array and transform that into an array of the same length but with each individual item transformed.
Filter transforms an array into a smaller array.
FilterNot does the same thing as filter but inverted.
There are lots of array transformations like this on the array object but what to do if you can find one that fits, that is where reduce comes in.
Map, filter and filterNot are all list transformations they turn your list into something else but they are all pretty specific but reduce is not. Reduce is the multi tool on list transformations, it can be used to express any list transformation.
Reduce is the super list transformation that you can fall back on if you can’t find a prebuilt list transformation that fits your problem.
Now we have done a lot of talking without code which means that you guys have died of boredom. You can pause here and do some stretching.
Let’s have a look at this array.
Our mission is to summarise the amounts. I’m going to show you how to do this using reduce but first let me make a for loop. Let’s have a look at this.
var totalAmount = 0
for (index in amounts.indices) {
totalAmount += amounts[index]
}
we created a variable called totalAmount and we loop through the orders and for every order we take the amount and add it to the totalAmount.
Let’s reimplement this using reduce. Just like map or filter reduce is a function on the array object and just like map and filter it takes a callback function but unlike map and filter it wants an object. You can think of this object as a starting point for our sum it’s going to be zero and this sum is going to be passed as the first argument(sum) to the reduce callback. Just like map and filter reduce will also receive the iterated item but it’s going to be the second argument(amount).
var totalAmount = amounts.reduce(fun(sum, amount): Int {
return sum + amount
})
We’re here taking the sum that we received the initial value and we’re adding the amount to it. So this is going to take the first amount and add zero point and return. This return value will in turn be passed as the sum in the next situation which in turn will add its amount to it and return that and so on until we are finished.
In this story I talked about how reduce fits into your toolbox. How math and filter and filterNot are all list transformations and how reduce is the multi tool of list transformations which you can use if you can’t find a pre-built transformation that fits your purposes.
I’ve also shown you a super basic example of what you can use reduce for. However, the example that I showed you is extremely basic and really doesn’t showcase the extreme power of this function so I want to spend the next story on reduce as well talk about how reduce combines with other list transformations. I want to talk about how reduce can create much more complex and interesting objects than just the sum that I showed you in the example I am going to sell you on how powerful this function is. Do not miss it.