降低

过滤,缩小和映射:
轻按一下即可转换收藏。
这些功能上的朋友,
您将清除的代码,
输入不可变,没有陷阱。

映射和过滤器引起了很多关注,但是我说减少是重要的一环。 或者,如果您对效率感兴趣,该怎么做:您可以使用reduce来构建地图和过滤器。 如果您只想学习一种,请选择减少。

功能朋友

Map具有对序列中的每个项目执行某些操作并收集结果的有用行为。

let words = ["hello", "there"] 
let shoutyWords = words.map { $0.uppercased() }
// ["HELLO", "THERE"]

map的输入是大小为n的序列,输出的大小也为n

接下来,使用过滤器可以确定序列中要保留(和丢弃)的项目。

 let numbers = 0...10 
let evenNumbers = numbers.filter { $0 % 2 == 0 }
// [0, 2, 4, 6, 8, 10]

输出大小将介于0到n之间,具体取决于要过滤的事物数量。

减少什么?

减少减少

像其他两个操作一样, reduce接受一个序列作为输入,但是它的输出更为通用:它可以是您想要的任何东西!

对于循环的每一转, reduce将先前的输出与当前项目一起传递。 这意味着您可以在迭代之间保留一些状态,并且可以根据需要构建输出。

对于第一次,您需要提供一个初始启动器“结果”值。 这意味着reduce需要两个参数:

  1. 初始结果值。
  2. 产生下一个部分结果的闭包。

Reduce将部分结果和下一个值作为闭包的参数传递。

使用减少

reduce的教科书示例是找到总数:

 let primes = [3, 7, 31, 127] 
let sum = primes.reduce(0) { (result, item) in
return result + item
}

第一次通过, reduce将调用closure(0, 3) ,其中0是初始值,3是第一项。 现在的结果是0 + 3或3。

下一次通过循环, reduce将调用closure(3, 7) ,其中3是上次的结果,而7是下一项。 等等。

最后,我们将把数组[Int]转换为Int类型的最终结果。

建筑减少

让我们看一下标准库中reduce的构建方式。 和往常一样,代码将在下面内联,您可以在GitHub上的SequenceAlgorithms.swift中自己查看代码。

一旦获得了稍微粗糙的功能签名,它就很短了:

 public func reduce( 
_ initialResult: Result,
_ nextPartialResult:
(_ partialResult: Result, Iterator.Element) throws -> Result )
rethrows -> Result {

这里有很多Result类型-这是描述最终返回值将是什么的通用类型。 这可能与Iterator.Element不同,后者是序列中事物的类型。

initialResult参数的类型为Result ,需要作为第一个参数传递到函数中。

第二个参数是针对序列中每个值运行的闭包。 闭包本身传递了两个参数:

  1. 从上一次迭代返回的结果。
  2. 序列中的下一项。

最后, throwsrethrows关键字允许闭包引发错误。 如果需要,这些将被重新链接到原始呼叫者。

累积结果

当我们遍历序列时, accumulator变量将保存累加结果。

 var accumulator = initialResult 

我们将从传递给函数的初始结果开始。

接下来是重要的迭代步骤:

 for element in self { 
accumulator = try nextPartialResult(accumulator, element)
}

每次通过循环,累加器都会被闭包返回的新的部分值替换。 同样,这里的闭包采用上一个结果和下一个元素。

仅需一行:

 return accumulator 

最后,剩下要做的就是返回最后一个结果。

建筑图

如何使用reduce构建map ? 为简单起见,我们将使用数组而不是序列。

让我们从reduce工作方式来考虑map

  • 结果类型将是一个数组
  • 初始值应为空数组
  • 对于循环的每一圈,将一个项目添加到数组中
 extension Array { 
func mapUsingReduce(
_ closure:
(_ item: Iterator.Element) -> OutElement) -> [OutElement] {
return self.reduce([]) { (partial, item) in
return partial + [closure(item)]
}
}
}

通用参数OutElement是输出数组中元素的类型。 该方法使用闭包来执行将Iterator.Element转换为OutElement的转换步骤。

reduce调用在这里是预期的:从一个空数组开始,并在每次循环时都将其添加到累积数组中。

您能想到如何使用reduce编写filter吗? sort怎么sort ? 您还能想到什么其他用途? 与实际map这种方式做map效率如何?

结束括号

在这种情况下,学习如何使用锤子意味着每个问题开始看起来都像钉子一样(纠结另一句话)。 每当我需要对数组进行某种操作时,我就开始考虑如何使用reduce

但这并不意味着我实际上使用了 reduce并不是每个问题的最佳解决方案! 我喜欢它的原因是让我仔细考虑以下基础知识:初始值,增量步骤以及如何缓慢建立返回值。

下载 Reduce.playground 来签出代码并 亲自试用

}

Interesting Posts