ref – http://sketchytech.blogspot.com.by/2015/06/swift-what-do-map-and-flatmap-really-do.html
https://chrisbrandow.svbtle.com/swift-map-vs-flatmap
Map
Operate on the contents of the array. Maps unwraps a container ( array, dictionary…etc) , transforms value with supplied function and rewraps result.
1 2 3 4 |
let arr = [1,2,3,4,5,6] let temp = arr.map{ print($0) } |
output of each element:
1
2
3
4
5
6
Let’s apply adding 2 to each element
1 2 3 4 |
let arr = [1,2,3,4,5,6] let temp = arr.map{ print($0+2) } |
3
4
5
6
7
8
Let’s return it as an array
1 2 3 4 |
let arr = [1,2,3,4,5,6] let temp = arr.map{ $0+2 } |
[3, 4, 5, 6, 7, 8]
In this example, for each element in the array, let’s add 2.
So if you use print($0), you can see that each element is an integer.
And thus, we are able to add 2 to it.
Flat Map
flatMap unwraps a container (array, dictionary…etc), transforms value with supplied function and rewraps either a raw value, or the non-nil value of a contained result.
nil values are thrown out.
Flattening bottom most array
FlatMap doesn’t operate on the contents of the array, it operates on the array itself.
If you flatten an normal array, it defaults down to the element because we’r “pushing down”. If the bottom most array gets pushed down, they become elements.
If an array of an array gets pushed down, it simply goes down one level.
1 2 3 4 |
let arr = [1,2,3,4,5,6] let flatMapArr = arr.flatMap { $0. } |
In our case, $0. would then get the properties of the integer type. This shows that the bottom most array gets flattened to elements.
Flattening arrays
1 2 3 4 5 |
let arr = [[1,2,3,4,5,6]] let flatMapArr = arr.flatMap { $0.count } print(flatMapArr) // 6 |
If we have an array within an array, it would flatten everything, and get it as an array. In this case $0 is an array, and thus,
we can use property count. As mentioned previously, this array is not the bottom most array, and we simply push the array down one level to
[1, 2, 3, 4, 5, 6]
we apply $0.count to the array, and get 6 back. 6 is stored in an array, which is then returned back to us
1 2 3 4 |
let arr = [[1,2,3,4,5,6]] let flatMapArr = arr.flatMap { print("array is - \($0)") } |
What about array of array of array?
1 2 3 4 5 |
let arr2 = [[[1,2,3,4,5,6]]] let flatMapArr2 = arr2.flatMap { print("array is - \($0)") print("array count is - \($0.count)") } |
It becomes [[1, 2, 3, 4, 5, 6]]
array of array of array of array?
1 2 3 4 5 |
let arr3 = [[[[1,2,3,4,5,6]]]] let flatMapArr3 = arr3.flatMap { print("array is - \($0)") print("array count is - \($0.count)") } |
[[[1, 2, 3, 4, 5, 6]]]
Pretty straightforward.
Applying flatMap to bottom most array turns the array into individual elements.
Applying flatMap to array in an array, simply brings it down one level.
Let’s see an combination in action. Here, we see 2 arrays inside an array. They are not bottom most array and
hence are simply flattened down 1 step:
element is [1, 2, 3, 4, 5, 6]
element is [7, 8, 9]
$0.count would bring us 6 from the 1st element (which is an array of 6 ints)
and 3 from the 2nd element (which is an array of 3 ints)
it then returns us the array with the results: [6,3]
1 2 3 4 5 6 7 8 9 10 |
//in this example, flat map mapped out an array with 2 arrays in there // element 1 - [1, 2, 3, 4, 5, 6] // element 2 - [7, 8, 9] print("--------------") let arr4 = [[1,2,3,4,5,6], [7,8,9]] let flatMapArr4 = arr4.flatMap { // print("element is \($0)") $0.count } print("---------------") |
Double FlatMap
1 2 3 4 5 6 |
print("--------------") let arr5 = [[1,2,3,4,5,6], [7,8,9, [10,11,12]]] let flatMapArr5 = arr5.flatMap { print($0) } print("---------------") |
Now, let’s add an array in the 2nd array.
When we do a flat map, we get something like this:
element is [1, 2, 3, 4, 5, 6]
element is [7, 8, 9, [10, 11, 12]]
Let’s see what happens if we flatten it again!
1 2 3 4 5 6 7 8 |
print("--------------") let arr5 = [[1,2,3,4,5,6], [7,8,9, [10,11,12]]] let flatMapArr5 = arr5.flatMap { $0.flatMap { print($0) } } print("---------------") |
Hence when applying our rules mentioned above,
when flatMap gets applied a 2nd time to
[1, 2, 3, 4, 5, 6], it becomes:
1
2
3
4
5
6
because its a bottom most array.
for [7, 8, 9, [10, 11, 12]], it becomes:
7
8
9
[10, 11, 12]
flatMap nil array
So the idea is, map rewraps the results inside of the array, resulting in an array of contained strings and nils.
flatMap places only the non-nil contained value into the array, resulting in an array of data ONLY.
Let’s take a look at flatMap first:
1 2 3 4 5 6 7 8 |
let element : String? = nil let array = [element, element, element] print(array) // [nil, nil, nil] let result = array.flatMap{ // flatten it. base array becomes element print($0) // prints "nil" } |
If you were to process flatMap, you have a base array of nils. You flatten it, you get 3 element of nils.
You would then return nil for all the elements, the resulting array will be empty.
Thus, you’ll get an empty array if you have an
array of nil calling flatMap.
1 2 3 4 |
let result = array.flatMap{ // flatten it. base array becomes element $0 // returns nil for the array creation } print(result) |
output:
[]
map nil array
The flatMap is pretty much the same as map, except that the return value of the closure in map is not allowed to return nil, while the closure of map can return nil.
Now let’s see what happens if we use map.
We create an array of optional Strings. There is a separator element there in which we give it nil
1 2 |
let separator : String? = nil let section4 = [separator] |
Hence at this point it is, [nil]
When we map and print the element, we see that its nil
1 2 3 |
let resulting2 = section4.map { // we apply to each element print($0) // prints nil } |
Thus, we return nil to the array creation. The difference is that if we return nil to the array under map, due to the definition
of map (which is apply so and so to the element), we basically apply NOTHING to the nils, then return them back to the array creation.
that is why we still see the nil.
1 2 3 4 |
let resulting2 = section4.map { $0 } print(resulting2) |
output:
[nil]