swift常用高阶函数

2019-08-19  本文已影响0人  SPIREJ

swift常用的高阶函数mapflatMapfilterreduce

1. map

/// -参数转换:映射闭包。接受一个“变换”元素作为其参数,并返回转换后的值(相同或不同类型的值)。
/// -返回:包含转换后的元素的数组序列。
@inlinable public func map<T>(_ 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<SegmentOfResult>(_ transform: (Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence
1. map和flatMap的区别

相同点:
mapflatMap都可以用在OptionalsSequenceTypes上(如:数组、字典等)。

不同点:
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]

请注意上面使用mapflatMap,带有返回数组的转换的结果。实际上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<ElementOfResult>(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]

/// -参数转换:接受此元素的闭包,序列作为它的参数,并返回一个可选值。
/// -返回:调用“transform”的非“nil”结果的数组序列的每个元素。
/// -复杂度:O(*m* + *n*),其中*n*是这个序列的长度和*m*是结果的长度。
@inlinable public func compactMap<ElementOfResult>(_ 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<Result>(_ 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。当序列用完时,从闭包返回给调用者。
如果序列没有元素,则永远不会执行nextPartialResultinitialResult是调用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 还可以实现 mapfilter 并且时间复杂度变为O(n) 原来 mapfilter 的时间复杂度是O(n*n)

extension Array {
    func mMap<U>(transform: (Element) -> U) -> [U] {
        return reduce([], {
            $0 + [transform($1)]
        })
    }
    
    func mFilter (includeElement: (Element) -> Bool) -> [Element] {
        return reduce([]) { includeElement($1) ? $0 + [$1] : $0 }
    }
}

写在最后

我们看SequenceTypes上的方法和函数有这么多,学无止境,慢慢探索

上一篇下一篇

猜你喜欢

热点阅读