Swift的高阶函数

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值