楔子
问题:给定一个数组,找出里面所有的偶数
- 最先想到的方法是遍历数组,找出所有的偶数
- 如果用函数式编程,可以用如下代码解决
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
let events = numbers.filter { (num : Int) -> Bool in
return num % 2 == 0
}
- 方法解析
- filter接受一个闭包
- 闭包本身有一个参数,表示数组中的元素
- 返回值是一个Bool类型,用于过滤符合条件的元素
- 当满足条件时,就会将满足条件的元素放到数组中
- 优点:如果是找出奇数、3的倍数等等,只需改变下闭包中的表达式即可
面向对象与函数式编程
面向对象
现在要对一个数组进行处理,我可以封装一个工具类,类中可以提供如下方法:
- 获取数组中的偶数
- 对数组中的元素进行排序
- 其它各种能想得到的方法
但是,不能考虑到所有的情况。其实,要对数组进行怎样的处理,调用者最清楚。如果能让调用者将对数组处理的操作传过来就完美了
函数式编程
以Array
为例,如果系统没有提供filter函数,我们可以自己扩展一个类似的函数
- 函数的参数一个对数组中元素的操作
- 既然是操作,操作本身也就是一个函数
- 操作的参数是数组中的一个元素
extension Array {
func personlFilter(oprationFunc : (Int) -> Bool) -> [Int] {
var tempArray = [Int]()
for item in self {
if oprationFunc(item as! Int) {
tempArray.append(item as! Int)
}
}
return tempArray
}
}
// 使用
let newEvents = numbers.personlFilter { (num) -> Bool in
return num % 3 == 0
}
如果想让代码更通用,我们还可以使用范型,例如获取字符串数组中包含a
的字符串
reduce
reduce
是函数式编程中一个常用的函数,它的作用是将集合中的元素按照某种方式合并,合并的规则由调用者决定,代码如下
let totoal = numbers.reduce(5) { (num1 : Int, num2 : Int) -> Int in
return num1 + num2
}
上述代码是将numbers数组中的元素求和。reduce
接收两个参数
- 参数一是合并前的初始化的值
- 参数二是一个闭包,闭包中的第一个参数是每次合并后的值,第二个参数是下一次要合并的值
map
map
可以对数组中的每一个元素做一次处理。代码如下
let animals = ["Dragon", "Cat", "Tiger", "fdakjfdakf", ""]
let animalCount = animals.map { (str : String) -> Int in
let length = str.count
return length
}
// [Optional(6), Optional(3), Optional(5), Optional(10), nil]
map巧用示例
根据已知数组,创建一个count相同的对应的数组
let titles = ["头条", "视频", "娱乐", "要问", "体育" , "科技" , "汽车" , "时尚" , "图片" , "游戏" , "房产"]
// 创建每一页对应的controller
let childViewControllers: [ContentViewController] = titles.map { _ -> ContentViewController in
let controller = ContentViewController()
controller.view.backgroundColor = UIColor.randomColor
return controller
}
compactMap
Swift 4.1后,compactMap
代替了flatMap
,它们与map
类似,但compactMap
会自动剔除返回数组中的nil
,并把Optional解包
let animalFlapCount = animals.compactMap { (str: String) -> Int? in
let length = str.count
guard length > 0 else {
return nil
}
return length
}
//[6, 3, 5, 10]
可以看出,与map
返回的结果相比,少了nil
项
示例
实现一个函数:求0~100(包括0和100)中为偶数并且恰好是其它数字平方的数字
- 通常的解法
func evenSquare(from a: Int, to b: Int) ->[Int] {
var result = [Int]()
for num in a...b where ((num % 2) == 0) {
if (a...b).contains(num * num) {
result.append(num * num)
}
}
return result
}
- 使用函数式编程的解法
func evenSquare(from :Int, to : Int) -> [Int] {
/*let res = [Int]()
let res = (from...to).map { (num) -> Int in
return num*num
}.filter { (num) -> Bool in
return num % 2 == 0
}*/
let res = (from...to).map{ $0 * $0}.filter{ $0 % 2 == 0}
return res
}
- 首先使用map将将0~10映射成对应的平方数
- 利用filter将偶数过滤出来
网友评论