swift常用高阶函数

swift常用的高阶函数mapflatMapfilterreduce

1. map

/// -参数转换:映射闭包。接受一个“变换”元素作为其参数,并返回转换后的值(相同或不同类型的值)。
/// -返回:包含转换后的元素的数组序列。
@inlinable public func map<T>(_ transform: (Element) throws -> T) rethrows -> [T]

来看一个例子,就能秒懂
在本例中,首先使用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]

/// 第一次返回的是数组,也可以map连写
let res = cast.map { (str) -> String in
    str.lowercased()
    }.map { (str) -> Int in
        str.count
}
// 'res' = [6, 6, 3, 4]

let res1 = cast.map {
    $0.lowercased()
    }.map {
        $0.count
}
// 'res1' = [6, 6, 3, 4]

2. flatMap

/// -参数转换:接受此元素的闭包,返回一个序列或集合。
/// -返回:生成的扁平数组。
/// -复杂度:O(*m* + *n*),其中*n*是这个序列的长度和*m*是结果的长度。
@inlinable public func flatMap<SegmentOfResult>(_ transform: (Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence
1. map和flatMap的区别

相同点:
mapflatMap都可以用在OptionalsSequenceTypes上(如:数组、字典等)。

不同点:
map对这个序列的每个元素进行转换。
flatMap会将转换(transform)函数的返回类型先拍扁,在组合成本身的复合类型

看一个例子

let numbers = [1, 2, 3, 4]
let mapped = numbers.map { Array(repeating: $0, count: $0) }
// [[1], [2, 2], [3, 3, 3], [4, 4, 4, 4]]

let flatMapped = numbers.flatMap { Array(repeating: $0, count: $0) }
// [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]

请注意上面使用mapflatMap,带有返回数组的转换的结果。实际上s.flatMap(transform)相当于Array(s.map(transform). joined())

2. compactMap

Swift4.1新加入的新特性compactMap;
对序列的每个元素进行转换,返回非nil结果

@available(swift, deprecated: 4.1, renamed: "compactMap(_:)", message: "Please use compactMap(_:) for the case where closure returns an optional value")

public func flatMap<ElementOfResult>(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]

/// -参数转换:接受此元素的闭包,序列作为它的参数,并返回一个可选值。
/// -返回:调用“transform”的非“nil”结果的数组序列的每个元素。
/// -复杂度:O(*m* + *n*),其中*n*是这个序列的长度和*m*是结果的长度。
@inlinable public func compactMap<ElementOfResult>(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]

看一个例子
map返回有可选值nil
compactMap返回的是剔除可选值的结果

let possibleNumbers = ["1", "2", "three", "///4///", "5"]

let mapped: [Int?] = possibleNumbers.map { str in Int(str) }
//[Optional(1), Optional(2), nil, nil, Optional(5)]

let compactMapped: [Int] = possibleNumbers.compactMap { str in Int(str) }
// [1, 2, 5]
3. 什么时候用 flatMap、compactMap

当类型转换时有可能装换为可选类型的时候,用compactMap,不会装换为可选类型的咱们直接用flatMap

比如我们有一个数组

let array = ["Apple", "Orange", "Puple", "sss"]

我们想要返回每个元素的长度的时候,转换时返回类型是Int?时,这个时候不能确保转换成功,就需要用compactMap

let array = ["Apple", "Orange", "Puple", "sss"]

let sss = array.flatMap { (str) -> String in
    str
}

let arr2 = array.compactMap { a -> Int? in
    return a.count
}

3. filter

filter过滤器,可以取出数组中符合条件的元素,重新组成一个新的数组

let numbers = [1,2,3,4,5,6]
let evens = numbers.filter { $0 % 2 == 0 }
// [2, 4, 6]

4. reduce

有的时候我们需要把所有元素的值合并成成一个新的值,就用到了reduce

/// -参数:
/// - initialResult:用作初始累积值的值。“initialResult”第一次被传递给“nextPartialResult”执行闭包。
/// - nextPartialResult:一个包含累积值和的闭包, 将序列中的一个元素转换成一个新的累加值,待用在“nextPartialResult”闭包或返回到的下一个调用中
/// -返回:最终的累积值。如果序列没有元素,结果是“initialResult”。
/// -复杂度:O(*n*),其中*n*是序列的长度。
@inlinable public func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result

来看下面这个例子

let numbers = [1, 2, 3, 4]
let numberSum = numbers.reduce(0, { x, y in
    x + y
})
// numberSum == 10

当调用numbers.reduce(_:_:)时,执行以下步骤:
1。使用initialResult——0调用nextPartialResult闭包,在这种情况下——调用numbers的第一个元素,返回sum:' 1 '
2。使用前一个调用的返回重复调用闭包值和序列的每个元素。
3。当序列用完时,从闭包返回给调用者。
如果序列没有元素,则永远不会执行nextPartialResultinitialResult是调用reduce(_:_:)的结果。

1. 合并成的新值不一定跟原数组中元素的类型相同

let numbers = [1,3,5,6,9,4,0,0,9,8,8]
let tel = numbers.reduce("") {
    "\($0)" + "\($1)"
}
//13569400988 String类型

2. ruduce 还可以实现 mapfilter 并且时间复杂度变为O(n) 原来 mapfilter 的时间复杂度是O(n*n)

extension Array {
    func mMap<U>(transform: (Element) -> U) -> [U] {
        return reduce([], {
            $0 + [transform($1)]
        })
    }
    
    func mFilter (includeElement: (Element) -> Bool) -> [Element] {
        return reduce([]) { includeElement($1) ? $0 + [$1] : $0 }
    }
}

写在最后

我们看SequenceTypes上的方法和函数有这么多,学无止境,慢慢探索

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

推荐阅读更多精彩内容