swift常用的高阶函数
map
、flatMap
、filter
、reduce
1. map
/// -参数转换:映射闭包。接受一个“变换”元素作为其参数,并返回转换后的值(相同或不同类型的值)。
/// -返回:包含转换后的元素的数组序列。
@inlinable public func map(_ transform: (Element) throws -> T) rethrows -> [T]
来看一个例子,就能秒懂
在本例中,首先使用map
转换数组中的名称
转换为小写字符串,然后计算它们的字符数。
let cast = ["Vivien", "Marlon", "Kim", "Karl"]
let lowercaseNames = cast.map { $0.lowercased() }
// 'lowercaseNames' == ["vivien", "marlon", "kim", "karl"]
let letterCounts = cast.map { $0.count }
// 'letterCounts' == [6, 6, 3, 4]
/// 第一次返回的是数组,也可以map连写
let res = cast.map { (str) -> String in
str.lowercased()
}.map { (str) -> Int in
str.count
}
// 'res' = [6, 6, 3, 4]
let res1 = cast.map {
$0.lowercased()
}.map {
$0.count
}
// 'res1' = [6, 6, 3, 4]
2. flatMap
/// -参数转换:接受此元素的闭包,返回一个序列或集合。
/// -返回:生成的扁平数组。
/// -复杂度:O(*m* + *n*),其中*n*是这个序列的长度和*m*是结果的长度。
@inlinable public func flatMap(_ transform: (Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence
1. map和flatMap的区别
相同点:
map
和flatMap
都可以用在Optionals和SequenceTypes上(如:数组、字典等)。
不同点:
map
对这个序列的每个元素进行转换。
flatMap
会将转换(transform
)函数的返回类型先拍扁,在组合成本身的复合类型
看一个例子
let numbers = [1, 2, 3, 4]
let mapped = numbers.map { Array(repeating: $0, count: $0) }
// [[1], [2, 2], [3, 3, 3], [4, 4, 4, 4]]
let flatMapped = numbers.flatMap { Array(repeating: $0, count: $0) }
// [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
请注意上面使用map
和flatMap
,带有返回数组的转换的结果。实际上s.flatMap(transform)
相当于Array(s.map(transform). joined())
。
2. compactMap
Swift4.1
新加入的新特性compactMap
;
对序列的每个元素进行转换,返回非nil结果
@available(swift, deprecated: 4.1, renamed: "compactMap(_:)", message: "Please use compactMap(_:) for the case where closure returns an optional value")
public func flatMap(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]
/// -参数转换:接受此元素的闭包,序列作为它的参数,并返回一个可选值。
/// -返回:调用“transform”的非“nil”结果的数组序列的每个元素。
/// -复杂度:O(*m* + *n*),其中*n*是这个序列的长度和*m*是结果的长度。
@inlinable public func compactMap(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]
看一个例子
map
返回有可选值nil
compactMap
返回的是剔除可选值的结果
let possibleNumbers = ["1", "2", "three", "///4///", "5"]
let mapped: [Int?] = possibleNumbers.map { str in Int(str) }
//[Optional(1), Optional(2), nil, nil, Optional(5)]
let compactMapped: [Int] = possibleNumbers.compactMap { str in Int(str) }
// [1, 2, 5]
3. 什么时候用 flatMap、compactMap
当类型转换时有可能装换为可选类型的时候,用compactMap
,不会装换为可选类型的咱们直接用flatMap
比如我们有一个数组
let array = ["Apple", "Orange", "Puple", "sss"]
我们想要返回每个元素的长度的时候,转换时返回类型是Int?
时,这个时候不能确保转换成功,就需要用compactMap
let array = ["Apple", "Orange", "Puple", "sss"]
let sss = array.flatMap { (str) -> String in
str
}
let arr2 = array.compactMap { a -> Int? in
return a.count
}
3. filter
filter
过滤器,可以取出数组中符合条件的元素,重新组成一个新的数组
let numbers = [1,2,3,4,5,6]
let evens = numbers.filter { $0 % 2 == 0 }
// [2, 4, 6]
4. reduce
有的时候我们需要把所有元素的值合并成成一个新的值,就用到了reduce
/// -参数:
/// - initialResult:用作初始累积值的值。“initialResult”第一次被传递给“nextPartialResult”执行闭包。
/// - nextPartialResult:一个包含累积值和的闭包, 将序列中的一个元素转换成一个新的累加值,待用在“nextPartialResult”闭包或返回到的下一个调用中
/// -返回:最终的累积值。如果序列没有元素,结果是“initialResult”。
/// -复杂度:O(*n*),其中*n*是序列的长度。
@inlinable public func reduce(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result
来看下面这个例子
let numbers = [1, 2, 3, 4]
let numberSum = numbers.reduce(0, { x, y in
x + y
})
// numberSum == 10
当调用numbers.reduce(_:_:)
时,执行以下步骤:
1。使用initialResult
——0
调用nextPartialResult
闭包,在这种情况下——调用numbers
的第一个元素,返回sum:' 1 '
。
2。使用前一个调用的返回重复调用闭包值和序列的每个元素。
3。当序列用完时,从闭包返回给调用者。
如果序列没有元素,则永远不会执行nextPartialResult
和initialResult
是调用reduce(_:_:)
的结果。
1. 合并成的新值不一定跟原数组中元素的类型相同
let numbers = [1,3,5,6,9,4,0,0,9,8,8]
let tel = numbers.reduce("") {
"\($0)" + "\($1)"
}
//13569400988 String类型
2. ruduce
还可以实现 map
和 filter
并且时间复杂度变为O(n)
原来 map
和 filter
的时间复杂度是O(n*n)
extension Array {
func mMap(transform: (Element) -> U) -> [U] {
return reduce([], {
$0 + [transform($1)]
})
}
func mFilter (includeElement: (Element) -> Bool) -> [Element] {
return reduce([]) { includeElement($1) ? $0 + [$1] : $0 }
}
}
写在最后
我们看SequenceTypes上的方法和函数有这么多,学无止境,慢慢探索