使用閉包自定義排序
當(dāng)你開始深入研究集合 (包括數(shù)組,字典袜香,集合set)時(shí),閉包就派上了用場鲫惶。之前蜈首,我們使用數(shù)組的sorted()方法對(duì)數(shù)組進(jìn)行排序。現(xiàn)在我們可以通過閉包,自定義排序欢策。
調(diào)用sorted()來獲得數(shù)組排序后的版本:
let names = ["ZZZZZZ", "BB", "A", "CCCC", "EEEEE"]
names.sorted()
// ["A", "BB", "CCCC", "EEEEE", "ZZZZZZ"]
通過自定義閉包吆寨,可以更改數(shù)組的排序細(xì)節(jié)。定義一個(gè)尾隨閉包踩寇,如下所示:
names.sorted {
$0.count > $1.count
}
// ["ZZZZZZ", "EEEEE", "CCCC", "BB", "A"]
現(xiàn)在啄清,數(shù)組按字符串的長度排序,字符串的長度優(yōu)先
使用閉包遍歷集合
在Swift中俺孙,集合實(shí)現(xiàn)了一些非常方便的特性辣卒,這些特性通常與函數(shù)式編程相關(guān)聯(lián),這些特性以函數(shù)的形式出現(xiàn)睛榄,可以將這些功能應(yīng)用到集合上荣茫,以對(duì)其執(zhí)行操作。
轉(zhuǎn)換元素
對(duì)集合中的元素進(jìn)行循環(huán)场靴,并執(zhí)行操作:
let values = [1, 2, 3, 4, 5, 6]
values.forEach {
print("\($0): \($0*$0)")
}
這個(gè)循環(huán)遍歷集合中每個(gè)元素并打印值和值的平方
過濾元素
var prices = [1.5, 10, 4.99, 2.30, 8.19]
let largePrices = prices.filter {
return $0 > 5
}
創(chuàng)建一個(gè)數(shù)組啡莉,表示商店中商品的價(jià)格。過濾大于$5的價(jià)格旨剥,你可以使用filter函數(shù)咧欣。這個(gè)函數(shù)看起來是這樣的:
func filter(_ isIncluded: (Element) -> Bool) -> [Element]
這意味著filter只接受一個(gè)參數(shù),它是一個(gè)閉包(或函數(shù))轨帜,它接受一個(gè)元素并返回一個(gè)Bool魄咕。然后,filter函數(shù)返回一個(gè)元素?cái)?shù)組阵谚。在此上下文中蚕礼,元素指的是數(shù)組中項(xiàng)目的類型。在上面的例子中梢什,元素是Double類型
是否應(yīng)該保留該值,這取決于閉包是返回true或false奠蹬。從filter返回的數(shù)組將包含閉包返回true的所有元素。
在例子中嗡午,largeprice將包含:(10, 8.19)
注意:從filter(以及所有這些函數(shù))返回的數(shù)組是一個(gè)新數(shù)組囤躁。原數(shù)組根本沒有修改。
想象一下荔睹,你正在進(jìn)行一場促銷活動(dòng)狸演,想要把所有的商品都降價(jià)到原來的90%。有一個(gè)很方便的函數(shù)僻他,叫做map宵距,它可以做到這一點(diǎn):
let salePrices = prices.map {
return $0 * 0.9
}
map函數(shù)接受一個(gè)閉包,在數(shù)組中的每個(gè)條目都會(huì)執(zhí)行它吨拗,并返回一個(gè)包含所有執(zhí)行結(jié)果的新數(shù)組满哪,并保持該順序婿斥。在這種情況下,
salePrices將包含:[1.35, 9, 4.491, 2.07, 7.371]
map函數(shù)可以用來改變類型
let userInput = ["0", "11", "haha", "42"]
let numbers1 = userInput.map {
Int($0)
}
用戶輸入字符串并將它們轉(zhuǎn)換成整數(shù)數(shù)組哨鸭。但是它們需要是可選的民宿,因?yàn)閺膕tring到Int的轉(zhuǎn)換可能會(huì)失敗。
如果你想要過濾掉無效的(丟失的)值像鸡,可以使用flatMap():
let numbers2 = userInput.flatMap {Int($0)}
flatMap幾乎和map一樣活鹰,只是它創(chuàng)建了一個(gè)Int數(shù)組,并拋出了缺失值只估。
另一個(gè)方便的函數(shù)叫做reduce志群。這個(gè)函數(shù)取一個(gè)起始值和一個(gè)閉包。閉包取兩個(gè)值:當(dāng)前值和數(shù)組中的元素仅乓。閉包的返回值作為當(dāng)前值參數(shù)傳入閉包赖舟。
這可以用于價(jià)格數(shù)組來計(jì)算總數(shù)蓬戚,比如:
let sum = prices.reduce(0) {
return $0 + $1
}
初始值為0夸楣。然后,閉包計(jì)算當(dāng)前值的和加上當(dāng)前迭代的值子漩。這樣就計(jì)算了數(shù)組中所有值的總和豫喧。在這種情況下,sum將是:
26.98
現(xiàn)在你已經(jīng)知道了filter幢泼、map和reduce紧显,希望能夠清楚地了解這些函數(shù)的強(qiáng)大程度,特別是閉包的語法缕棵。在幾行代碼中孵班,你已經(jīng)可以從集合中計(jì)算相當(dāng)復(fù)雜的值。
這些函數(shù)也可以用于字典招驴。想象一下篙程,你在你的倉庫里用一個(gè)字典來表示你的股票,用這個(gè)價(jià)格映射到商品的數(shù)量上别厘。你可以用它來計(jì)算你的股票的總價(jià)值:
let stock = [1.5: 5, 10: 2, 4.99: 20, 2.30: 5, 8.19: 30]
let stockSum = stock.reduce(0) {
return $0 + $1.key * Double($1.value)
}
在本例中虱饿,reduce函數(shù)的第二個(gè)參數(shù)是一個(gè)tuple,它包含來自字典元素的鍵和值触趴。計(jì)算值需要類型轉(zhuǎn)換氮发。
結(jié)果是:384.5
還有另一種形式的reduce,當(dāng)你需要將集合變?yōu)閿?shù)組或字典時(shí)冗懦,它是有用的爽冕。它叫做reduce(into:_:)。你可以這樣使用:
let farmAnimals = ["??": 5, "??": 10 ,"??": 50 ,"??": 1]
let allAnimals = farmAnimals.reduce(into: []) {
(result, this: (key: String, value: Int)) in
for _ in 0 ..< this.value {
result.append(this.key)
}
}
它與其他版本的執(zhí)行完全相同披蕉,只是不從閉包返回什么颈畸。相反前塔,每個(gè)迭代都給你一個(gè)可變的值來處理。這樣承冰,在這個(gè)示例中只有一個(gè)數(shù)組被創(chuàng)建并添加元素华弓。。
還有一些不同的功能困乒,在你需要切割的時(shí)候會(huì)很有用寂屏。
dropFirst
let removeFirst = prices.dropFirst()
let removeFirstTwo = prices.dropFirst(2)
dropFirst函數(shù)接受一個(gè)默認(rèn)值為1的參數(shù),并返回一個(gè)數(shù)組娜搂,其中包含從前面刪除的元素迁霎。在這種情況下,結(jié)果如下:
removeFirst = [10, 4.99, 2.30, 8.19]
removeFirstTwo = [4.99, 2.30, 8.19]
就像dropFirst一樣百宇,也存在從數(shù)組末尾移除元素的dropLast考廉。是這樣的:
dropLast
let removeLast = prices.dropLast()
let removeLastTwo = prices.dropLast(2)
這些結(jié)果如你所料,如下:
removeLast = [1.5, 10, 4.99, 2.30]
removeLastTwo = [1.5, 10, 4.99]
可以獲取數(shù)組的第一個(gè)或最后一個(gè)元素携御,如下所示:
let firstTwo = prices.prefix(2)
let lastTwo = prices.suffix(2)
這里昌粤,prefix返回?cái)?shù)組前面的元素,suffix返回 數(shù)組后面的元素啄刹。該函數(shù)的結(jié)果為:
firstTwo = [1.5, 10]
lastTwo = [2.30, 8.19]