This is day 29 of my 30 day Elm challenge
Yesterday was fun, but I'm really exhausted today. Maybe it's because I'm almost done with the 30 days, and I need a break.
I sure am glad I didn't commit to 100 days. :D
This is the most unmotivated I've felt since starting this challenge, so today I decided to write about map, filter and reduce.
Going from for loops to these functions really improved my JavaScript code and my experience, and I was happy to see them in Elm too.
- 1. In depth documentation
- 2. Array.map / List.map
- 3. Array.map / List.indexedMap
- 4. Array.filter / List.filter
- 5. Array.reduce / List.foldl
- 6. Conclusion
1. In depth documentation
I'm only going to explain some simple use cases. Afterwards, make yourself some hot beverage, and read these:
JavaScript array methods:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#instance_methods
Elm list functions:
https://package.elm-lang.org/packages/elm/core/latest/List
2. Array.map / List.map
Applies a function to each element in a list.
2.1. JavaScript
[1, 2, 3].map(number => number + 1) // [2, 3, 4]
2.2. Elm
In Elm, the list usually comes last.
List.map (\number -> number + 1) [1, 2, 3] -- [2, 3, 4]
However, there's a nicer way to do this.
Using the pipeline |>
, the result to its left gets passed as the last argument to the function that comes after it:
[1, 2, 3] |> List.map (\number -> number + 1) -- [2, 3, 4]
I think this syntax is intuitive, and very nice to look at.
3. Array.map / List.indexedMap
This is just how the standard JavaScript map function works.
Elm has two map functions: List.map
with no index, and List.indexedMap
.
3.1. JavaScript
const languages = ["JavaScript", "Elm", "Scratch"]
// Using parentheses to get implicit return on its own line
const withIndex = languages.map((language, index) => (
`${index}: ${language}`
))
console.log(withIndex)
// ["0: JavaScript", "1: Elm", "2: Scratch"]
3.2. Elm
languages = ["JavaScript", "Elm", "Scratch"]
withIndex = languages
|> List.indexedMap (\index language ->
(index |> Debug.toString) ++ ": " ++ language
)
As you can see, the order of index and element are the other way around in Elm.
Also, Elm doesn't have very nice string interpolation, and you have to explicitly convert other types to a string.
4. Array.filter / List.filter
Keeps the items that return true.
The name "filter" is kind of ambiguous to me, so think of it as keepIfTrue
instead.
4.1. JavaScript
The => number <=
part looks weird, so I added a second option that looks nicer to me.
[1, 2, 3, 4, 5].filter(number => number <= 3) // [1, 2, 3]
[1, 2, 3, 4, 5].filter(number => (
number <= 3
))
4.2. Elm
[1, 2, 3, 4, 5] |> List.filter (\number -> number <= 3)
Note that Elm's filter function doesn't provide an index.
5. Array.reduce / List.foldl
Reduces an array into one single variable.
JavaScript has reduce
and reduceRight
, while Elm has foldl
and foldr
. Left and right just specify if we're looping from the beginning or the end of the list.
In the beginning, I just thought of reduce
as the way you get a sum, but now I want to use it for everything.
It's not a replacement for more readable standard functions, although that can be very fun. Anyway:
5.1. JavaScript
We have a variable total
, which will be updated from inside a loop that's going through an array.
Many people use the term accumulator
, which sounds more fancy than total
.
Here's an example without reduce
:
let array = [1, 2, 3, 4, 5]
let total = 0 // Could also be a string, array, object, etc.
for (const item of array) {
total = total + item
}
console.log(total) // 15
However, other parts of the code might use the accumulator, so it's safer to let reduce
handle it:
const sumOf1to5 = [1, 2, 3, 4, 5].reduce((total, item) => {
return total + item
}, 0)
console.log(sumOf1to5) // 15
total
refers to 0
, which is the initial value, and item
is each separate value in the array.
Also, the really cool people don't use variable names that make sense:
const sumOf1to5 = [1, 2, 3, 4, 5].reduce((a, b) => a + b) // 15
5.2. Elm
Firstly, Elm has its own sum and product functions, so you don't need to implement these with List.foldl
:
List.sum [1, 2, 3, 4, 5] -- 15
List.sum (List.range 1 100) -- 5050
List.product (List.range 1 5) -- 120
List.foldl
works the same way if you want:
[1, 2, 3, 4, 5] |> List.foldl (\item total -> total + item) 0
Beyond that, you can do a bunch of crazy stuff, but I'm not in the mood for that now.
6. Conclusion
I hope this helped, or maybe even steered you away from for loops.
map, filter and reduce are a lot of fun, and they really improved my JavaScript code and experience when I learned them.
See you tomorrow!
Top comments (0)