Written by Sheldon, please find me with #iOSBySheldon in Github, Youtube, Facebook, etc.
It is exaggerating to say we don't need to use for
loop or while
loop any more but we can take advantage of the Swift language built in functions to do loops. If I give you a question now.
Q: Assuming we have an optional nested array, please calculate the production of the values that are less than 5. let numbers: [[Int]?] = [[1, 3], nil, [2], [5, 10], nil, [4]]
, what is your best approach to do it?
And you know the solution that I am talking about is following Swift functions:
- Map
- FlatMap / CompactMap
- Reduce
- Filter
- Sort
Above functions are all useful for collections (array / dictionary pairs). The only reason I want to mention this is that compactMap is coming maybe in Swift 4.1 or 4.2 to replace flatMap, I just want to maybe give you a bit summary at the same time for all of them. Assuming we will be having an array, and I will give examples of the use of those functions.
Map is just pretty much equal to for number in numbers
let numbers: [Int]() = [2, 4, 1, 3]
_ = numbers.map { String($0) } // ["2", "4", "1", "3"]
NOTE: $0 means each element in the collection
FlatMap can do what ever Map can do while it has two more functions, filter nil & flatten nested array.
let optionalNumbers: [Int?] = [2, nil, 3]
let numbers: [Int] = optionalNumbers.flatMap { $0 } // [2, 3]
let nestedNumbers: [[Int]] = [[2, 4], [3]]
let numbers: [Int] = nestedNumbers.flatMap { $0 } // [2, 4, 3]
FlatMap can do one thing at a time, in this case, you need two FlatMaps
let optionalNestedArray: [[Int]?] = [[2], nil, [4, 3]]
let numbers: [Int] = optionalNestedArray.flatMap{ $0 }.flatMap{ $0 } // [2, 4, 3]
compactMap
is actually just a naming changes, because flatMap
has worse performance than Map, and it can do what map can do. Therefore, Apple tries to clarify the naming to make only use flatMap
/compactMap
when it is really needed.
Reduce is to take all elements for calculations
let numbers: [Int] = [2, 4, 1, 3]
let sum = numbers.reduce(0, +) // 2+4+1+3 = 10
let sum = numbers.reduce(0, { $0 + $1 }) // 10
NOTE: 0
is the initial value we need to consider, for sum, 0 is what we need
NOTE: $0
is current number, $1 is next number in the array
let product = numbers.reduce(1, *) // 2*4*1*3 = 24
let product = numbers.reduce(1, { $0 * $1 }) // 24
NOTE: 1
will be the needed initial value for production
Obviously, you can do other calculations if you want.
Filter is my favorite, using Filter, we can find all targeted value.
let numbers: [Int] = [1, 2, 3, 5]
let bigNumbers = numbers.filter { $0 >= 3 } // [3, 5]
let biggerNumbers = numbers.filter { $0 >= 5 } // [5]
NOTE: the filtered numbers are returning an Array!
Sort is pretty common used, as we can easily to ascending or descending orders
let numbers: [Int] = [2, 3, 1]
let ascdNumbers = numbers.sorted() // [1, 2, 3]
let ascdNumbers = numbers.sorted(by: { $0 < $1 }) // [1, 2, 3]
let dsNumbers = numbers.sorted(by: { $0 > $1 }) // [3, 2, 1]
Here I will give you a question and you will solve it in peace.
Q: Assuming we have an optional nested array, please calculate the production of the values that are less than 5.
let numbers: [[Int]?] = [[1, 3], nil, [2], [5, 10], nil, [4]]
A: Result will be easily calculated as:
let result: Int = numbers
.flatMap({$0})
.flatMap({$0})
.filter({ $0 <= 5 })
.reduce(1, *)
If u will, you can replace flatMap will compactMap as:
let result: Int = numbers
.compactMap({$0})
.compactMap({$0})
.filter({ $0 <= 5 })
.reduce(1, *)
Life can be easier without for/while loops!
Good !!