美文网首页
Swift(二)高阶函数

Swift(二)高阶函数

作者: 孔雨露 | 来源:发表于2019-08-10 06:37 被阅读0次

    @TOC

    swift常用高阶函数

    swift中比较常用的高阶函数有:map、flatMap、filter、reduce
    更多swift相关教程可以参考极客学院文章

    1. map

    map可以对数组中的每一个元素做一次处理

    1. 先通过下面实例代码了解一下map的用法
    // 计算字符串的长度
    let stringArray = ["Objective-C", "Swift", "HTML", "CSS", "JavaScript"]
    func stringCount(string: String) -> Int {
        return string.characters.count
    }
    stringArray.map(stringCount)
    
    stringArray.map({string -> Int in
        return string.characters.count
    })
    
    // $0代表数组中的每一个元素
    stringArray.map{
        return $0.characters.count
    }
    
    1. 我们来查看一下map在swift中的定义
      我们看到它可以用在 Optionals 和 SequenceType 上(如:数组、词典等)。
      代码:
    public enum Optional<Wrapped> : _Reflectable, NilLiteralConvertible {
        /// If `self == nil`, returns `nil`.  Otherwise, returns `f(self!)`.
        @warn_unused_result
        public func map<U>(@noescape f: (Wrapped) throws -> U) rethrows -> U?
    }
    
    extension CollectionType {
        /// Returns an `Array` containing the results of mapping `transform`
        /// over `self`.
        ///
        /// - Complexity: O(N).
        @warn_unused_result
        public func map<T>(@noescape transform: (Self.Generator.Element) throws -> T) rethrows -> [T]
    }
    
    

    源码中的一些关键字在这里介绍一下:
    @warn_unused_result:表示如果没有检查或者使用该方法的返回值,编译器就会报警告。
    @noescape:表示transform这个闭包是非逃逸闭包,它只能在当前函数map中执行,不能脱离当前函数执行。这使得编译器可以明确的知道运行时的上下文环境(因此,在非逃逸闭包中可以不用写self),进而进行一些优化

    1. 对 Optionals进行map操作
      简要的说就是,如果这个可选值有值,那就解包,调用这个函数,之后返回一个可选值,需要注意的是,返回的可选值类型可以与原可选值类型不一致:
    ///原来类型: Int?,返回值类型:String?
    var value:Int? = 1
    var result = value.map { String("result = \($0)") }
    /// "Optional("result = 1")"
    print(result)
    
    
    var value:Int? = nil
    var result = value.map { String("result = \($0)") }
    /// "nil"
    print(result)
    
    1. 对SequenceType进行map操作

    我们可以使用map方法遍历数组中的所有元素,并对这些元素一一进行一样的操作(函数方法)。map方法返回完成操作后的数组。

    在这里插入图片描述

    我们可以对比一下用传统的For-in操作和map操作:

    1. 传统写法:
    var values = [1,3,5,7]
    var results = [Int]()
    for var value in values {
        value *= 2
        results.append(value)
    }
    //"[2, 6, 10, 14]"
    print(results)
    //传统的For-in实现起来代码很多,不简介,而且效率没有高阶函数高。
    
    2. 使用map高阶函数
    let results = values.map ({ (element) -> Int in
        return element * 2
    })
    //"[2, 6, 10, 14]"
    
    此外还有更加精简的写法:
    let results = values.map { $0 * 2 }
    //"[2, 6, 10, 14]"
    3. 
    

    通过上面的代码对比,我们可以看出高阶函数精简写法是多么的优雅,就像写诗一样。下面我们来探究一下怎么就精简这么短小了呢,连return语句都不需要了

    • 第一步
      由于闭包的函数体很短,所以我们将其改写成一行:
    let results = values.map ({ (element) -> Int in return element * 2 })
    //"[2, 6, 10, 14]"
    
    
    • 第二步
      由于我们的闭包是作为map的参数传入的,系统可以推断出其参数与返回值,因为其参数必须是(Element) -> Int类型的函数。因此,返回值类型,->及围绕在参数周围的括号都可以被忽略:
    let results = values.map ({ element  in return element * 2 })
    //"[2, 6, 10, 14]"
    
    
    • 第三步
      单行表达式闭包可以通过省略return来隐式返回闭包的结果:
      由于闭包函数体只含有element * 2这单一的表达式,该表达式返回Int类型,与我们例子中map所需的闭包的返回值类型一致(其实是泛型),所以,可以省略return。
    let results = values.map ({ element  in element * 2 })
    //"[2, 6, 10, 14]"
    
    
    • 第四步
      参数名称缩写(Shorthand Argument Names),由于Swift自动为内联闭包提供了参数缩写功能,你可以直接使用0,1,$2...依次获取闭包的第1,2,3...个参数。
      如果您在闭包表达式中使用参数名称缩写,您可以在闭包参数列表中省略对其的定义,并且对应参数名称缩写的类型会通过函数类型进行推断。in关键字也同样可以被省略:
    let results = values.map ({ $0 * 2 })//$0即代表闭包中的第一个参数。
    //"[2, 6, 10, 14]"
    
    
    • 第五步
      尾随闭包,由于我们的闭包是作为最后一个参数传递给map函数的,所以我们可以将闭包表达式尾随:
    let results = values.map (){ $0 * 2 }
    //"[2, 6, 10, 14]"
    

    如果函数只需要闭包表达式一个参数,当您使用尾随闭包时,您甚至可以把()省略掉:

    let results = values.map { $0 * 2 }
    //"[2, 6, 10, 14]"
    

    2. flatMap

    1. flatMap返回后的数组中不存在nil,同时它会把Optional解包
    let array = ["Apple", "Orange", "Puple", ""]
    
    let arr1 = array.map { a -> Int? in
        let length = a.characters.count
        guard length > 0 else { return nil }
        return length  
    }
    arr1 // [{some 5}, {some 6}, {some 5}, nil]
    
    let arr2 = array.flatMap { a-> Int? in
        let length = a.characters.count
        guard length > 0 else { return nil}
        return length    
    }    
    arr2 // [5, 6, 5]
    
    1. flatMap还能把数组中存有数组的数组(二维数组、N维数组)一同打开变成一个新的数组
    let array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    
    let arr1 = array.map{ $0 }
    arr1 // [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    
    let arr2 = array.flatMap{ $0 }
    arr2 // [1, 2, 3, 4, 5, 6, 7, 8, 9]
    
    1. flatMap也能把两个不同的数组合并成一个数组,这个合并的数组元素个数是前面两个数组元素个数的乘积
    let fruits = ["Apple", "Orange", "Puple"]
    let counts = [2, 3, 5]
    
    let array = counts.flatMap { count in
        fruits.map ({ fruit in
             return fruit + "  \(count)"            
        })   
    }
    array // ["Apple 2", "Orange 2", "Puple 2", "Apple 3", "Orange 3", "Puple 3", "Apple 5", "Orange 5", "Puple 5"]
    

    3. filter

    filer:过滤,可以对数组中的元素按照某种规则进行一次过滤

    // 筛选出字符串的长度小于10的字符串
    let stringArray = ["Objective-C", "Swift", "HTML", "CSS", "JavaScript"]
    func stringCountLess10(string: String) -> Bool {
        return string.characters.count < 10
    }
    stringArray.filter(stringCountLess10)
    
    stringArray.filter({string -> Bool in
        return string.characters.count < 10
    })
    
    // $0表示数组中的每一个元素
    stringArray.filter{
        return $0.characters.count < 10
    }
    

    4. reduce

    reduce:计算,可以对数组的元素进行计算

    // 将数组中的每个字符串用‘、’拼接
    let stringArray = ["Objective-C", "Swift", "HTML", "CSS", "JavaScript"]
    
    func appendString(string1: String, string2: String) -> String {
        return string1 == "" ? string2 : string1 + "、" + string2
    }
    // reduce方法中的第一个参数是初始值
    stringArray.reduce("", appendString)
    
    stringArray.reduce("", {(string1, string2) -> String in
        return string1 == "" ? string2 : string1 + "、" + string2
    })
    
    // $0表示计算后的结果, $1表示数组中的每一个元素
    stringArray.reduce("", {
        return $0 == "" ? $1 : $0 + "、" + $1
    })
    

    参考博客,教程:
    http://wiki.jikexueyuan.com/project/swift/chapter2/07_Closures.html

    相关文章

      网友评论

          本文标题:Swift(二)高阶函数

          本文链接:https://www.haomeiwen.com/subject/mnrljctx.html