swift函数

swift高阶函数

map

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]

compactMap

解包所有可选选项并丢弃nil值

// 转化为 [Int?] 因为内部元素可能不符合转化规则
let strings = ["1", "2", "fish"]
let a = strings.map {Int($0)}
let b = strings.compactMap {Int($0)}
print(a)
print(b)
// [Optional(1), Optional(2), nil]
// [1,2]

flatMap

过滤nil值,降低数组维度,降低可选项维度

与 map 的区别:

  • flatMap 会降低数组维度,过滤nil值,但是每次操作只执行一种功能,优先执行过滤 nil的操作。

嵌套情况见下:

let arr = [[[1,1,1],2],[3,4], nil, nil]
// 优先处理nil值
let arr1 = arr.flatMap{ $0 }
let arr2 = arr.flatMap{ $0 }.flatMap{ $0 }
print(arr1, arr2, separator: "\n")
// [[[1, 1, 1], 2], [3, 4]]
// [[1, 1, 1], 2, 3, 4]

总结:

  • map 和 compactMap 返回的元素不改变原先的类型
  • 在嵌套 map 的情况下,flatMap 会将 String 降维至 Character
  • 在不是嵌套 map 的情况下
    • 若原序列是 String 序列,不指定类型或指定为[String]:flatMap 将元素处理成 Character
    • 指定[Any]类型,flatMap 与 map、compactMap 一致,不改变原先类型。

作用于可选对象

map()方法也存在于可选对象上:如果一个可选类型有值,map会获取这个值,经过map的闭包处理变为另外一个值,如果这个可选类型的值为nil,那么不会执行map闭包,而是直接返回nil

// 如果name包含字符串,则map()会将解包,将其转换为“ Hi, name包含的字符串”,然后将整个拼接后的字符串放入一个可选对象中并返回以存储在greeting中。
// 如果name不包含字符串为nil,map()将直接返回nil给greeting。
let name: String? = valueOrNil(id: 97)
let greeting = name.map { "Hi, \($0)" }
print(greeting ?? "Unknown user")

类似的 flatMap() 同样可以作用于可选对象,区别是map闭包不能return nil,而flatmap可以

var value: Double? = 10
var newValue: Double? = value.flatMap { v in
    if v < 5.0 {
        return nil
    }
    return v / 5.0
}
// newValue is now Optional(2)

newValue = newValue.flatMap { v in
    if v < 5.0 {
        return nil
    }
    return v / 5.0
}
// now it's nil

使用场景:替代三目运算符

一般在使用可选对象时,必须分有值和nil值的情况,运用到三目运算符时肯定会使用强制解包,这样很不优雅。
使用 map 代替,如果可选值为 nil,则会直接返回 nil,不会进入后面的闭包。

// 时间操作
var date: NSDate? = ...
// var formatted: String? = date == nil ? nil : NSDateFormatter().stringFromDate(date!)
var formatted: String? =  date.map(NSDateFormatter().stringFromDate)

// 获取String字面量的值
func ageToString(age: Int?) -> String {
    //return age == nil ? "Unknown age" : "She is (age!) years old"
    return age.map { "She is ($0) years old" } ?? "Unknown age"
}

// 在数组中找到某项
func find(identifier: String) -> Item? {
    return items.indexOf({$0.identifier == identifier}).map({items[$0]})
}

filter

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

let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
//筛选偶数值
let evens = numbers.filter{$0 % 2 == 0} //等同于
let even = numbers.filter{(num) -> Bool in
      num % 2 == 0
}

//筛选奇数值
let odds = numbers.filter{$0 % 2 == 1} //等同于
let odd = numbers.filter{(num) -> Bool in
      num % 2 == 1
}

reduce(归纳合并成一个元素)

  • reduce(initial, combineClosure): 从第一个初始值开始对其进行combineClosure操作,递归式地将序列中的元素合并为一个元素
  • combineClosure:规则闭包,要返回如何将元素合并,有两个参数
    • $0 代表累加器,初值等于 initial
    • $1 代表遍历数组得到的一个元素
var languages = ["Swift", "OC", "java"]
let r = languages.reduce("_", {$0 + $1}) //等同于
let r = languages.reduce("_") { (result, next) -> String in
    print("result: \(result)")
    print("next: \(next)")
    return result + next
}
print(r)

/**
result: _
next: Swift
result: _Swift
next: OC
result: _SwiftOC
next: java
_SwiftOCjava
*/

print([10, 20, 5].reduce(1, { $0 * $1 }) == 1000) // true
// 极简形式 [10, 20, 5].reduce(1, *)

值的注意的问题

  • 仅传入计算符号 "+" "*" 作为一个 combinator 函数是有效的
    • 它仅仅是对 lhs(Left-hand side,等式左侧) 和 rhs(Right-hand side,等式右侧) 做计算处理,最后返回结果值
[0, 1, 2, 3, 4].reduce(0, +)
[1, 2, 3, 4].reduce(1, *)
  • 性能问题:
    使用高阶函数之前多考虑实现方案,通常情况下,map 和 filter 所组成的链式结构会引入性能上的问题,因为它们需要多次遍历你的集合才能最终得到结果值,这种操作往往伴随性能损失。
// 初始序列(即 [0,1,2,3,4])被重复访问了三次之多
[0, 1, 2, 3, 4].map({ $0 + 3}).filter({ $0 % 2 == 0}).reduce(0, combine: +)

// 可用 reduce 完全替换实现,极大提高执行效率:
[0, 1, 2, 3, 4].reduce(0, { (ac, r) in 
  if (r + 3) % 2 == 0 {
   return ac + r + 3
  } else {
   return ac
  }
})

// for-loop 版本
var ux = 0
for i in 0...100000 {
    if (i + 3) % 2 == 0 {
      ux += (i + 3)
    }
}
5

更多范式

  • min:返回列表中的最小项。[1,5,2,9,4].minElement() 方法更胜一筹。
  • unique:剔除列表中重复的元素。最好的解决方式是使用集合(Set)

sort

let Arr = [13, 45, 27, 80, 22, 53]
// 完整
let sort1 = Arr.sorted { (a: Int, b: Int) -> Bool in
    return a < b
}
// 简略
let sort2 = Arr.sorted { $0 < $1 }
// 极简
let sort3 = Arr.sorted(by: <)

参考文档Swift5 高阶函数

你可能感兴趣的:(swift函数)