Swift4 Day98:map、forEach、compactMap、filter、reduce、sorted、reverse
Functional programming:higher-order function note
map()
loop Array 中的每個 item 對它進行操作 用
- 用 map 改寫 for 迴圈算字的長度
- Array 中的各個 item uppercased、lowercased 或轉成 String
- 或用 Ternary operator r (
a ? b : c
) 篩選 Array 內容超過 85 分 Pass 小於的 Fail 與 45~55 間的為 “Within average” 反之 ”Outside average”
- 用 map 搭配 sqrt 開根號
- map 是會保留 nil 的(補充:反之 compactMap / flatMap 則是不會保留 nil ),所以會回傳 Optional(100) 而不是 100
let i: Int? = 50let j = i.map { $0 * 2 }// Optional(100)
利用 map 這個特性改寫下面的
let username2 = aliceBirthday(in: 1995)let formattedUsername2: Stringif let username = username2 {formattedUsername2 = "Welcome, \(username)!"} else {formattedUsername2 = "Unknown user"}
forEach()
感覺跟 map 很像,loop Array 中的每個 item。
最大的不同在於 map 會 return 一個新的 Array,forEach 則不會 return 任何東西。如果 loop Array 後需要儲存為新的Array 使用 map,如果只是使用 Array item 內容使用 forEach 會是比較好的選擇。
flatMap
let numbers = [[1, 2], [3, 4], [5, 6]]
let joined = Array(numbers.joined()) //[1, 2, 3, 4, 5, 6]
你可以用 joined() 讓兩個 Array 合在一起,而 flatMap 則是結合 map 與 joined()的好方法
但如果 Array 中有 nil Swift 4.1後系統就會建議使用 compactMap
compactMap()
map 跟 compactMap 最大的差別是 map 會回傳 nil 跟optional ,compactMap則會濾掉 nil,直接回傳有值的部分。
可以用這個方法濾掉轉型失敗的 item ,例如以下 Stirng 轉 int 的應用場景
或用這種方式找出 subviews 中的 UILabel
let labels = view.subviews.flatMap { $0 as? UILabel }
filter()
可以找出除以三整除的數字
let fibonacciNumbers = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]let number = fibonacciNumbers.filter { $0 % 3 == 0 }//[3, 21]
搭配 hasPrefix 篩選出想要的 item 組合
let names = ["12", "11", "2312", "32131", "9998"]let result = names.filter { $0.hasPrefix("1") }print(result)//"["12", "11"]\n"
或搭配 contains 比對 String 中包含的 Array item
import Foundationlet words = ["Alice", "Crystal", "Nia"]let input = "Alice in wonderland"let result = words.filter { input.contains($0) }print(result)//["Alice"]
也可以用 Filter 做出類似 compactMap 的效果把 nil 篩選掉,但不同在於會回傳 Optional。
let words = ["Alice", "Crystal", nil]let result = words.filter { $0 != nil }print(result)//[Optional("Alice"), Optional("Crystal")]
用這個方法 filter Array 中的 value
let scores = ["Alice": 100, "Nia": 95, "Crystal": 90, "Annie": 85, "Joy": 60]let goodScores = scores.filter { $1 > 85 }print(goodScores.keys) //["Alice", "Nia", "Crystal"]
reduce()
可以用來相加數字
let scores = [100, 90, 95]let sum = scores.reduce(0, +) // 從 0 開始 對每個數相加//285let sum2 = scores.reduce(25, +)//310
或直接相加 String
let result = scores.reduce("") { $0 + String($1) }print(result) //1009095
或是用 reduce 算 Array 中的個數 count 不使用 for 迴圈
let names = ["Alice", "Crystal", "Annie"]let count = names.reduce(0) { $0 + $1.count } //17
算是不是所有字數都<4 ,只要其中一個字串<4就會是 false ,存在 $0 後繼續跟後面的字串對比
let names = ["Nia", "Alice", "Crystal"]let longEnough = names.reduce(true) { $0 && $1.count > 4}print(longEnough) //false
也可以用來找最長的字串
let names = ["Nia", "Alice", "Crystal"]let longest = names.reduce("") { $1.count > $0.count ? $1 : $0 }print(longest)// Crystal
或用 max 做相同的事,而 reduce 從”” 開始所以永遠有值, max 則需要
unwrap
let longest = names.max { $1.count > $0.count }print(longest)//Optional("Crystal")
Reducing a multi-dimensional array
合併 Array 的方法現在有三種了
let numbers = [ [1, 1, 2], [3, 5, 8], [13, 21, 34] ]let flattened: [Int] = numbers.reduce([]) { $0 + $1 }let flattened2 = numbers.flatMap { $0 }let flattened3 = Array(numbers.joined())print(flattened, flattened2, flattened3)//[1, 1, 2, 3, 5, 8, 13, 21, 34] [1, 1, 2, 3, 5, 8, 13, 21, 34] [1, 1, 2, 3, 5, 8, 13, 21, 34]
sorted()
用 string 去會去 sort character ,所以 10230 會比 11 排的還要前面,當比對10 與 11,就會把 10230 放在前面
let scoresString = ["1","11", "21", "32", "11111", "10230"]let sortedString = scoresString.sorted()print(sortedString)//["1", "10230", "11", "11111", "21", "32"]
而如果你想照數字大小排的話就要轉成 Int
let scoresInt = scoresString.compactMap { Int($0) }let sortedInt = scoresInt.sorted()print(sortedInt)//[1, 11, 21, 32, 10230, 11111]
也可以結合 compactMap ,用更簡潔的方式轉成 Int 再排序
let scoresInt = scoresString.compactMap { Int($0) }.sorted()
//[1, 11, 21, 32, 10230, 11111]
試著用更複雜的資料去 sorted,排序 age
struct Person {var name: Stringvar age: Int}let alice = Person(name: "Alice", age: 18)let crystal = Person(name: "Crystal", age: 25)let nia = Person(name: "Nia", age: 22)let annie = Person(name: "Annie", age: 2)let people = [alice, crystal, nia, annie]let sortedPeople = people.sorted { $0.age < $1.age }print(sortedPeople)//[__lldb_expr_1.Person(name: "Annie", age: 2), __lldb_expr_1.Person(name: "Alice", age: 18), __lldb_expr_1.Person(name: "Nia", age: 22), __lldb_expr_1.Person(name: "Crystal", age: 25)]
reverse()
把 Array 的順序倒換
var people = ["alice", "crystal", "nia", "annie"]people.reverse()//["annie", "nia", "crystal", "alice"]
整理一些常用的高階函數🙋♀️