前言
Swift的标准数组支持三个高阶函数:map,filter和reduce,以及map的扩展flatMap。Objective-C的NSArray没有实现这些方法,但是开源社区弥补了这个不足。
极大地体现了Swift的高大功能和优点。
了解闭包
阐述
Swift一大特性便是使用简洁的头等函数(闭包)语法代替了复杂的blocks语法。头等函数-即可将函数当作参数传递给其他的函数,或从其他的函数里返回出值,并且可以将他们设定为变量,或者将他们存储在数据结构中。
闭包的形式: ((参数) -> 返回值)
我们先写一个求立方的函数:
1
2
3
4//MARK: -- 立方
func cube(_ a: Float) -> Float{
return a*a*a
}求两数进行f函数运算后的平均值的函数
1
2
3func averageOfFunction(_ a: Float ,_ b: Float ,_ f: ((Float) -> Float)) -> Float{
return (f(a) + f(b))/2
}
进行调用,简化闭包
1
2
3
4
5
6
7
8
9
10
11
12
13
14//直接传参数和函数名
let sum1 = averageOfFunction(2, 3, cube)
//直接把闭包做为它的函数方法参数
let sum2 = averageOfFunction(2, 3, {(x : Float) -> Float in x*x*x })
//隐式推断输入值为一个Float
let sum3 = averageOfFunction(2, 3, {x -> Float in x*x*x })
//把retuen一起忽略
let sum4 = averageOfFunction(2, 3, {x in x*x*x })
//使用默认参数名,最简化地写法
let sum5 = averageOfFunction(2, 3, { $0*$0*$0 })
默认参数名补充
我们还可以忽略指定参数名,使用默认参数名$0(如果函数接收多个参数,使用$K作为第K-1个参数,如$0,$1,$2……)
在高阶函数中也会根据闭包的的简化来进行简化代码。
map函数
map需求
map用于将每个数组元素通过某个方法进行转换。
我们用一个Int类型数组,想把每个数后面添加一个字符“元”,把数组转成字符串数组1
2let moneyArray = [12,34,8,17,91,2,82]
var stringArray : [String] = []//结果数组
一般的思维
1
2
3
4for money in moneyArray {
stringArray.append("\(money)元")
}
print(stringArray)map的函数介绍
public func map
(_ transform: (Element) throws -> T) rethrows -> [T] 以一个命名函数transform作为参数,transform负责把元素Element转成类型T并返回一个类型T的数组。
在我们的事例中,T为Int,T为String,作为转换函数传给map的是一个把Int转成String
map的方法
1
2
3stringArray = moneyArray.map({ (a: Int) -> String in
return "\(a)元"
})
1 | //MARK: -- 可以直接把代码换成一个简化的简约闭包 |
filter
filter需求
filter用于选择数组元素中满足某种条件的元素。使用上面的例子,筛选出大于20的元素,结果应该是[34,91,82]
1
var filterArray : [Int] =[]//结果数组
一般的思维
1
2
3
4
5
6
7for money in moneyArray {
if money > 20{
filterArray.append(money)
}
}
print(filterArray)filter的函数介绍
public func filter(_ isIncluded: (Element) throws -> Bool) rethrows -> [Element]
以一个命名函数isIncluded作为参数,isIncluded返回true或者false,对原数组元素Element调用isIncluded时,只有返回true的元素会通过筛选,从而放入返回数组 [Element]中
filter的方法
1
2
3
4filterArray = moneyArray.filter({ (a: Int) -> Bool in
return a > 20
})
print(filterArray)
1
2
3
4
5
6
7
//MARK: — 一个简化的简约闭包
filterArray = moneyArray.filter({money in money > 30})
print(filterArray)
//MARK: -- 最简约的写法,采用默认参数
filterArray = moneyArray.filter({$0 > 30})
print(filterArray)
reduce
reduce需求
reduce方法把数组元素组合计算为一个值。我们使用上面例子计算数组元素的和,结果应该为246(12+34+8+17+91+2+82) 以及: 828102912(12 X 34 X 8 X 17 X 91 X 2 X 82)
1
var filterArray : [Int] =[]//结果数组
一般的思维
1
2
3
4
5
6
7
8
9
10
11
12
13//MARK: — 求和
var sum = 0
for money in moneyArray {
sum += money
}
print(sum)
//MARK: — 求乘积
var product = 1
for money in moneyArray {
product = product * money
}
print(product)reduce的函数介绍
Reduce便可用于快速完成这类操作,通过指定一个初始值和一个组合元素的方法.
public func reduce
( initialResult: Result, nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result 接收两个参数,一个为initialResult的命名参数,类型跟Result一样的的初始值参数,另一个是命名函数nextPartialResult,把Result类型和数组元素Element进行运算,得到一个Result,逐个运行算成后得到最终的Result,将其返回。
reduce的方法
1
2
3
4
5
6
7
8//MARK: --一个简化的简约闭包
let sum = moneyArray.reduce(0) { (a : Int, b : Int) -> Int in
return a + b
}
let product = moneyArray.reduce(1) { (a : Int, b: Int) -> Int in
return a * b
}
print("数组总和==\(result),数组乘积==\(product)”)
1 | //MARK: -- 最简约的写法,采用默认参数 |
特殊情况下可再简化
上面的都不是最简化的,其实最简化地写法是这样的:
1
2
3
4//MARK:— Swift中操作符可用着函数,可简化成:
let sum = moneyArray.reduce(0, +)
let product = moneyArray.reduce(1, *)
print("数组总和==\(sum),数组乘积==\(product)")
reduce可能是三个高阶函数中最难理解的一个。 需要注意的是nextPartialResult函数的两参数类型不同,Result为计算结果类型,Element为数组元素类型。
flatMap
flatMap介绍
比map更深一样,在自定义函数时,可能把元素生成更多的元素,然后会把这些元素都加到新的元素数组中去。
代码示例
1
2
3
4
5
6
7let oldArray = [20,10,30]
let newArray = oldArray.flatMap { (a : Int) -> [String] in
return ["\(a)元","\(a)分"]
}
print(newArray)
// 结果: ["20元", "20分", "10元ƒ", "10分", "30元", "30分”]1
2
3
4//MARK: -- 简约写法
let newArray = oldArray.flatMap({["\($0)元","\($0)分"]})
print(newArray)
// 结果: ["20元", "20分", "10元", "10分", "30元", "30分”]
对比map
1
2
3let newArr = oldArray.map({["\($0)元","\($0)分"]})
print (newArr)
// 结果: [["20元", "20分"], ["10元", "10分"], ["30元", "30分"]]对比一下结果就看出运算的不同之处了。map是由一个元素生成object,返回后替代原来的元素,数组的这个元素就成了是object,数组的这个元素就是object。而flatMap可以由一个元素生成一个数组newArr,结果数组在这个元素的位置插入newArr.count个数的newArr,结果数组的个数就增加了newArr.count元素了。
所以flatmap是map的扩展功能,因为它生成的不是单个元素,而可以是数组。
总结
数据比较大的时候,高阶函数会比传统实现更快,因为它可以并行执行(如运行在多核上),除非真的需要更高定制版本的map,reduce和filter,否则可以一直使用它们以获得更快的执行速度。
当使用map,filter,reduce的代码质量会更好。