在幕后看看Swift中的Map,Filter和Reduce的实现

一个函数接受一些输入,对它做一些事情并创建一个输出。功能有签名和正文。如果为函数提供相同的输入,则始终获得相同的输出。简而言之,这是函数的定义。

现在我们将通过仔细研究它们来讨论更多功能。我们将在Swift中探索更高阶的函数。将另一个函数作为输入或返回函数的函数称为高阶函数。

在Swift中,我们使用Map,Filter,Reduce。当我们使用这些功能时,它似乎很神奇。此时,您可能不知道幕后发生了什么。通过函数式编程的思想和方法来映射,过滤和减少工作。即使Swift不是一种纯粹的功能语言,它也可以让你做功能性的东西。

现在让我们一个接一个地看一下背景中发生的事情。首先,我们将为某些特定数据类型实现这些函数的基本版本,然后我们将尝试实现通用版本。

Map 函数

假设我们有一个整数数组,我们需要编写一个函数,在向原始数组的每个元素添加一些delta值之后返回一个新数组。我们可以使用如下的简单for循环轻松地为此编写函数:


func increment(by delta: Int, to array: [Int]) -> [Int] {
    var result: [Int] = []
    for element in array {
        result.append(element + delta)
    }
    return result
}

increment(by: 2, to: arr) //[4, 5, 6, 7]

现在我们需要另一个函数,它通过将原始数组的每个元素加倍来返回一个新数组。为此,我们可以像下面这样实现它:

var arr = [2, 3, 4, 5]

func square(_ array: [Int]) -> [Int]{
    var result: [Int] = []
    for element in array {
        result.append(element * element)
    }
    return result
}

square(arr) //[4, 9, 16, 25]

如果我们看一下上面这两个函数,我们就可以发现它们基本上都在做同样的事情。只有for循环内部的功能不同。它们都将Integer数组作为输入,使用for循环转换每个元素,并返回一个新数组。所以基本上主要是将每个元素转换为新的元素。

由于Swift支持高阶函数,我们可以编写一个函数,它将获取一个整数数组,将函数转换为输入,并通过将transform函数应用于原始数组的每个元素来返回一个新数组。

var arr = [2, 3, 4, 5]

func apply(for array: [Int], transform: (Int) -> Int) -> [Int] {
    var result: [Int] = []
    for element in array {
        result.append(transform(element))
    }
    return result
}

apply(for: arr) { $0 * 3 } //[6, 9, 12, 15]

但仍然存在以上问题:它只返回一个整数数组。例如,如果我们要求将输入整数数组转换为字符串数组,那么我们就不能用这个函数做到这一点。为此,我们需要编写适用于任何类型的通用函数。

func genericApply<T>(to array: [Int], transform: (Int) -> T) -> [T] {
    var result: [T] = []
    for element in array {
        result.append(transform(element))
    }
    return result
}

genericApply(to: arr) { String($0) } //["2", "3", "4", "5"]

我们可以在Array扩展中实现泛型函数,如下所示:

  1. 在Array Extension中声明一个map函数,它使用泛型类型T.
  2. 该函数采用类型(元素) - > T的函数作为输入
  3. 声明一个空结果数组,该数组在函数内部保存T类型的数据。
  4. 实现for循环迭代自身并调用transform函数将元素转换为T类型
  5. 将转换后的值附加到结果数组中
var array = ["boudhayan", "biswas"]

extension Array {
    func map<T>(_ transform: (Element) -> T) -> [T] {
        var result: [T] = []
        for element in self {
            result.append(transform(element))
        }
        return result
    }
}

array.map { $0.count }  //[9, 6]

这就是Map函数在Swift中的工作方式。如果我们需要实现map函数,那么我们将像上面一样实现它。所以基本上,它不会在数组中产生任何魔法 - 我们可以很容易地自己定义函数。

Filter函数

假设我们有一个整数数组,我们只想在数组中保留偶数。我们可以通过使用简单的lo来实现这一点。

let integers = [1, 2, 3, 4, 5, 6]

func evenIntegers(from array: [Int]) -> [Int] {
    var result: [Int] = []
    for element in array where element % 2 == 0 {
        result.append(element)
    }
    return result
}

evenIntegers(from: integers) //[2, 4 6]

再一次,我们有一个表示项目类文件名的字符串数组,我们只想保留.swift文件。这也可以通过以下单循环完成:

let projectFiles = ["classA.swift", "classB.swift", ".gitignore", "ReadMe.md"]

func swiftFiles(from array: [String]) -> [String] {
    var result: [String] = []
    for element in array where element.hasSuffix(".swift") {
        result.append(element)
    }
    return result
}

swiftFiles(from: projectFiles) //["classA.swift", "classB.swift"]

如果我们仔细研究上述两个函数的实现,那么我们就可以理解它们基本上做同样的事情 - 只有两个数组的数据类型不同。我们可以通过实现泛型过滤器函数来概括这一点,该函数将数组和函数作为输入,并且根据includeElement函数的输出,它决定是否在结果数组中添加元素。

extension Array {
    func filter(_ includeElement: (Element) -> Bool) -> [Element] {
        var result: [Element] = []
        for element in self where includeElement(element) {
            result.append(element)
        }
        return result
    }
}

Reduce函数

假设我们有一个整数数组,我们想要实现两个返回sum和元素乘积的函数。我们可以通过使用一个简单的for循环来实现它:

func sum(_ integers: [Int]) -> Int {
    var result = 0
    for element in integers {
        result += element
    }
    return result
}

func product(_ integers: [Int]) -> Int {
    var result = 1
    for element in integers {
        result *= element
    }
     return result
}

sum([1, 2, 3]) //6
product([2, 3, 4]) //24

现在不是拥有一个整数数组,而是说我们有一个字符串数组,我们想要连接数组中的所有元素:

var names = ["Boudhayan", "Biswas"]

func concatenate(_ strings: [String]) -> String {
    var result = ""
    for element in strings {
        result += element
    }
    return result
}

concatenate(names) //BoudhayanBiswas

这三个功能基本上都是一样的。它们将数组作为输入,初始化结果变量,迭代数组,并更新结果变量。

从这里我们可以实现一个适用于所有人的通用函数。为此,我们需要结果变量的初始值和在每次迭代中更新该变量的函数。

所以我们可以用以下定义实现泛型函数:

上述实现对于[Element]类型的任何输入数组都是通用的。它将计算类型T的结果。要工作,它需要类型T的初始值以分配给结果变量。然后,它需要一个类型(T,元素) - > T的函数,它将在每次迭代中用于for循环内部以更新结果变量。

感谢阅读!

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

推荐阅读更多精彩内容

  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    X先生_未知数的X阅读 15,937评论 3 118
  • 达州印象 ☆田秀 或如神鹰飞过千里铁山 也如欲上九天的图腾 州河欲图解什么 水波在戛云亭边拍响 ...
    兴安居士阅读 318评论 0 2
  • 清晨的你 是否推开窗 山顶的太阳 早已撒下这片柔光 和着清新的微风 轻抚你温柔的脸庞 远处不在远方 独是翻不过你的...
    即是我阅读 215评论 0 0
  • 有人说,人生若只如初见…… 有人说,人生每天都是直播…… 有人说,平平淡淡才是真…… 有人说,轰轰烈烈才不枉此生…...
    Jasper小黑阅读 723评论 2 2