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 高阶函数

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,809评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,189评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,290评论 0 359
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,399评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,425评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,116评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,710评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,629评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,155评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,261评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,399评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,068评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,758评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,252评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,381评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,747评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,402评论 2 358

推荐阅读更多精彩内容