Swift Map與CompactMap區別

Map與CompactMap區別

對於不同點,我們先說說相同點:
Map和FlatMap都可以用在Optionals和SequenceTypes上(如:數組、字典等)。

對於不同點:
先說說Swift4新加入的新特性compactMap;
flatMap會將transform函數的返回類型先拍扁,在組合成本身的複合類型,Swift標準庫有3個 flatMap

Sequence.flatMap<S>(_: (Element) -> S) 
    -> [S.Element] where S : Sequence
Optional.flatMap<U>(_: (Wrapped) -> U?) -> U?
Sequence.flatMap<U>(_: (Element) -> U?) -> [U]

在 Swift 4.1中引入的compactMap新函數實際上是對第三個方法的重命名。
map 最終將它們組成一個二維的數組;

flatMap相關

Sequence.flatMap區別

flatMap 中執行的 closure 返回的是同樣的數組,但是 flatMap 將每一個返回的數組都拍扁,取出它的元素,構成一個大的一維數組。

let numbers = [[1, 2, 3, 4], [5, 6], [7]]
let maped = numbers.map { $0 }
let flatMapped = numbers.flatMap { $0 }
print(maped)
print(flatMapped)
/// [[1, 2, 3, 4], [5, 6], [7]]
/// [1, 2, 3, 4, 5, 6, 7]

Optional.flatMap區別

Optional的版本知道的和日常使用的就沒有那麼多了。先仔細看一下這兩個函數的定義,區別僅在一個處:

func map<U>( transform: (Wrapped) -> U)  -> U?
func flatMap<U>( transform: (Wrapped) -> U?) -> U?

map是閉包內return爲非可選項,但最終返回值爲可選項,即閉包return後又套了一層可選項。
flatMap是閉包內return爲可選項,最終返回值也爲可選項,即閉包內return後對可選項進行解包,最終又套了一層可選項。
那麼什麼時候使用 Optional Chaining,什麼時候使用 Optional 的 Mapping 呢?
我認爲,他們的差異在於 receiver 在類型轉換過程中承擔的角色,Optional Chaining 中只能作爲 receiver,而 Optional Mapping 函數還能作爲參數,更爲通用,因而第一個例子只能用 Mapping 實現;另一個方面,Optional Chaining 只能寫成串聯表達式,而 closure 當中可以寫更復雜的轉換邏輯。

還是用例子來說明:

let possibleNumber: Int? = Int("42")
let nonOverflowingSquare = possibleNumber.flatMap { 
    x -> Int? in
    let (result, overflowed) = x.multipliedReportingOverflow(by: x)
    return overflowed ? nil : result
}

Optional.compactMap區別

衆所周知,flatMap可以作爲降維使用,除了 flat 之外其實還有 filter 的作用,在使用時容易產生歧義,所以社區認爲最好把第二個版本重新拆分出來,使用一個新的方法命名,就產生了這個提案 SE-0187。

最初這個提案用了filterMap這個名字,但後來經過討論,就決定參考了 Ruby 的Array::compact方法,使用compactMap這個名字。

如下是改版前後的代碼區別,可以看到用法相同,僅針對名字進行了更改。

Sequence.flatMap<U>(_ : (Element) -> U?) -> [U]
Sequence.compactMap<U>(_ : (Element)  -> U?) -> [U]

compactMap,可以把一個集合中的空值去除,並且返回一個去除nil值得數組
下面通過代碼例子說明下區別:

let numbers = ["1", "2", "three", "///5///", "5"]
let mapResult = numbers.map { (number) -> Int? in
    return Int(number)
}
print(mapResult)
// [Optional(1), Optional(2), nil, nil, Optional(5)]
let compactMapResult = numbers.compactMap { (number) -> Int? in
    return Int(number)
}
print(compactMapResult)
// [1, 2, 5]

相關文章:
Swift Map詳解.
Swift flatMap詳解.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章