捣腾swift 高阶函数map 、Filter 、 reduce

试着去使用 map 和 reduce,但这不是强制的。当合适的时候,使用 for 循环也无可厚非。高阶函数的意义是让代码可读性更高。但是如果使用 reduce 的场景难以
理解的话,强行使用往往事与愿违,这种时候简单的 for 循环可能会更清晰。

1.1.1、map

普通for循环

 let numGroup: [Int] = [1,2,3,4,5]
        var numGroupNew: [Int] = []
        for num in numGroup {
            numGroupNew.append(num * num)
        }

        print(numGroupNew) // [1, 4, 9, 16, 25]

尝试map函数
先看效果

let numGroupMap0: [Int] = numGroup.map { (num) -> Int in
            return num * num
        }
print(numGroupMap0)  // [1, 4, 9, 16, 25]

// 简化
let numGroupMap1: [Int] = numGroup.map { num in return num * num }
print(numGroupMap1)  // [1, 4, 9, 16, 25]

//再简化
let numGroupMap2 = numGroup.map { $0 * $0 }
print(numGroupMap2)  // [1, 4, 9, 16, 25]

好吧....最后就用了一行代码就完成了。
它很短而且比原来更清晰。所有无关的内容都被移除了。

map:可以对数组中的每一个元素做一次处理

1.1.2、flatMap

 let numGroupFlatMap = numGroup.flatMap { $0 * $0 }
 print(numGroupFlatMap)

等等...这好像和map一样嘛,也是对数组中的每一个元素做一次处理。
那他们两者有何区别呢,我们再试一下

let arrxx = array.map { $0.count}          //[5, 6, 6, 0]
let arryy = array.flatMap { $0.count}     //[5, 6, 6, 0]

这还是一样啊.... 再等等,一定是我的打开方式不对。我们展开再捋一下~

let array = ["apple", "orange", "banana", ""]
let arr1 = array.map { a -> Int? in
     let length = a.count
      guard length > 0 else { return nil }
      return length
 }
print(arr1) //[Optional(5), Optional(6), Optional(6), nil]
        
let arr2 = array.flatMap { a-> Int? in
    let length = a.count
    guard length > 0 else { return nil}
    return length
}
print(arr2) //[5, 6, 6]

发现了,不对,怎么map返回的数组都带Optional,最后空字符串也变成了nil
flatMap返回后的数组中不存在nil,同时它会把Optional解包

还有一个🌰

let group = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
let groupA = array.map{ $0 }

print(groupA) // [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
let groupB = array.flatMap{ $0 }
print(groupB) // [1, 2, 3, 4, 5, 6, 7, 8, 9]

原来flatMap还能把数组中存有数组的数组(二维数组、N维数组)一同打开变成一个新的数组

mapfilter随便举一个🌰

let fruits = ["Apple", "Orange", "Banana"]
let counts = [2, 3, 5]        
let array = counts.flatMap { count in
    fruits.map ({ fruit in
            return fruit + "  \(count)"
       })
  }

2、Filter

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

let nums = [1,2,3,4,5,6,7,8,9,10]
nums.filter { $0 % 2 == 0 } // [2, 4, 6, 8, 10]

连和之前的 map我们还能来个组合击

(1..<10).map { $0 * $0 }.filter { $0 % 2 == 0 } // [4, 16, 36, 64]

在喵神的 Swift 进阶书中提到

一个关于性能的小提示:如果你正在写下面这样的代码,请不要这么做!

bigArray.filter { someCondition }.count > 0

filter 会创建一个全新的数组,并且会对数组中的每个元素都进行操作。然而在上面这段代码中,这显然是不必要的。在这个情景下,使用 contains(where:) 更为合适:

bigArray.contains { someCondition }

3、reduce

reduce方法把数组元素组合计算为一个值。

传统实现:
var sum = 0
for money in moneyArray {
    sum = sum + money
}

再看看数字相乘
var product = 1
for money in moneyArray {
    product = product * money
}

那再看一下reduce如何实现

var sumReduce0 = moneyArray.reduce(0,{$0 + $1})
//简化 ~
var sumReduce1 = moneyArray.reduce(0,+)

他的方法为:

public func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result

他的的API文档

/// Returns the result of combining the elements of the sequence using the
    /// given closure.
    ///
    /// Use the `reduce(_:_:)` method to produce a single value from the elements
    /// of an entire sequence. For example, you can use this method on an array
    /// of numbers to find their sum or product.
    ///
    /// The `nextPartialResult` closure is called sequentially with an
    /// accumulating value initialized to `initialResult` and each element of
    /// the sequence. This example shows how to find the sum of an array of
    /// numbers.
    ///
    ///     let numbers = [1, 2, 3, 4]
    ///     let numberSum = numbers.reduce(0, { x, y in
    ///         x + y
    ///     })
    ///     // numberSum == 10
    ///
    /// When `numbers.reduce(_:_:)` is called, the following steps occur:
    ///
    /// 1. The `nextPartialResult` closure is called with `initialResult`---`0`
    ///    in this case---and the first element of `numbers`, returning the sum:
    ///    `1`.
    /// 2. The closure is called again repeatedly with the previous call's return
    ///    value and each element of the sequence.
    /// 3. When the sequence is exhausted, the last value returned from the
    ///    closure is returned to the caller.
    ///
    /// If the sequence has no elements, `nextPartialResult` is never executed
    /// and `initialResult` is the result of the call to `reduce(_:_:)`.
    ///
    /// - Parameters:
    ///   - initialResult: The value to use as the initial accumulating value.
    ///     `initialResult` is passed to `nextPartialResult` the first time the
    ///     closure is executed.
    ///   - nextPartialResult: A closure that combines an accumulating value and
    ///     an element of the sequence into a new accumulating value, to be used
    ///     in the next call of the `nextPartialResult` closure or returned to
    ///     the caller.
    /// - Returns: The final accumulated value. If the sequence has no elements,
    ///   the result is `initialResult`.

真的..辣么长,简直比农药里杨玉环的技能解释还长n倍。
大致总结一下就是
返回一个Result类型,以及接收两个参数,一个为类型Result的初始值,另一个为把类型为Result的元素和类型为Element的元素组合成一个返回Result的值的函数。

我们再看看API中的🌰

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

x为计算结果,y为数组元素,他们的类型可以不一样,x代表的是计算后返回得来的类型,y是数组元素的类型。

那这例子我们稍微调整一下

let numberStr = numbers.reduce("", { x, y in
     x + "\(y)"
})
 // numberStr == 1234

当然reduce还有很多骚操作。这篇只是个抛砖引玉~ 希望能给自己给大家一点点的收获。

相关推荐~
https://www.jianshu.com/p/6f45a6f99411
https://blog.csdn.net/youshaoduo/article/details/65629909

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

推荐阅读更多精彩内容