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

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

如今咱们将经过仔细研究它们来讨论更多功能。咱们将在Swift中探索更高阶的函数。将另外一个函数做为输入或返回函数的函数称为高阶函数。编程

在Swift中,咱们使用Map,Filter,Reduce。当咱们使用这些功能时,它彷佛很神奇。此时,您可能不知道幕后发生了什么。经过函数式编程的思想和方法来映射,过滤和减小工做。即便Swift不是一种纯粹的功能语言,它也可让你作功能性的东西。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]
复制代码

如今咱们须要另外一个函数,它经过将原始数组的每一个元素加倍来返回一个新数组。为此,咱们能够像下面这样实现它:bash

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循环转换每一个元素,并返回一个新数组。因此基本上主要是将每一个元素转换为新的元素。app

因为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扩展中实现泛型函数,以下所示:ui

  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来实现这一点。spa

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循环内部以更新结果变量。 #感谢阅读!

相关文章
相关标签/搜索