Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save SheldonWangRJT/791c85749051cf4b63b1590f08143156 to your computer and use it in GitHub Desktop.
Save SheldonWangRJT/791c85749051cf4b63b1590f08143156 to your computer and use it in GitHub Desktop.
Swift Map, FlatMap (CompactMap), Reduce, Filter & Sort

High Order Functions in iOS Swift

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:

  1. Map
  2. FlatMap / CompactMap
  3. Reduce
  4. Filter
  5. 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

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

FlatMap can do what ever Map can do while it has two more functions, filter nil & flatten nested array.

Filter Nil

let optionalNumbers: [Int?] = [2, nil, 3]
let numbers: [Int] = optionalNumbers.flatMap { $0 }      // [2, 3]

Flatten Nested Array

let nestedNumbers: [[Int]] = [[2, 4], [3]]
let numbers: [Int] = nestedNumbers.flatMap { $0 }        // [2, 4, 3]

Optional Nested Array

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

Reduce is to take all elements for calculations
let numbers: [Int] = [2, 4, 1, 3]

Sum

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

Multiply

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

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

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]

Final Challenge: A combination of all

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!

@Lyankar
Copy link

Lyankar commented Oct 5, 2018

Very nice.....

@ham118
Copy link

ham118 commented Jun 10, 2019

Good !!

@TomEstelrich
Copy link

Nice and simple way to go through all of them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment