为啥 Swift 中的过滤器会迭代集合两次?
Posted
技术标签:
【中文标题】为啥 Swift 中的过滤器会迭代集合两次?【英文标题】:Why does filters in Swift iterate the collection twice?为什么 Swift 中的过滤器会迭代集合两次? 【发布时间】:2014-06-03 21:56:20 【问题描述】:以下代码在 Swift 的 Playground 或 Console App 中:
let letters = ["A", "B", "C"]
letters.filter(
(x : String) -> Bool in
println("PRINT: \(x)")
return true
)
打印出来:
PRINT: A
PRINT: B
PRINT: C
PRINT: A
PRINT: B
PRINT: C
为什么它会遍历集合两次?
【问题讨论】:
不是说REPL正在打印filter
方法的结果吗?
不,它正在执行闭包 6 次
公平地说,filter
的规范并没有指定执行闭包的次数...
这听起来很可能是一个错误。我会告诉苹果。
header里面还有一个全局的filter
方法,不过还没想好怎么用……
【参考方案1】:
很可能filter
被实现为首先计算它需要存储的元素数量,然后在使用该数字确定新数组的存储分配大小后,再次循环以复制他需要保留的元素。
如果你总是返回false
,它只会循环一次,这意味着如果结果为空,它会优化第二个循环。
您可能希望将此视为一个错误,但它可能“按设计工作”:毕竟数组不是列表。
【讨论】:
您的回答非常符合事实,我很确定这正是幕后发生的事情。迄今为止最好的回复+1。但是Apple的实现不应该只是分配一个与源数组一样大的结果数组,然后在最后改变它的容量吗?不需要重复两次。 他们可以。他们没有。这是一个实施选择。根据其他实现细节,它可能是也可能不是最佳选择。【参考方案2】:它在 beta 5 中进行了修改。它现在只运行一次,打印 ABC
而不是 ABCABC
【讨论】:
【参考方案3】:filter
返回一个正在被 Playground 打印出来的数组。
/// Return a Array containing the elements `x` of `self` for which
/// `includeElement(x)` is `true`
func filter(includeElement: (T) -> Bool) -> T[]
我认为(6 times)
是不正确的,因为如果您在下面查看,true
只会返回 3 次。
编辑:以上内容不正确。
从玩多了,我只能说这只是filter
函数的行为。
letters.reverse().filter(
(x : String) -> Bool in
println("PRINT: \(x)")
return true
)
这将打印CBACBA
,因此它总是按顺序遍历数组两次。
letters.filter(
(x : String) -> Bool in
println("PRINT: \(x)")
if (x == "A")
return true
return false
)
这仍然打印ABCABC
,所以去算一下..
稍后我会去问一个 Swift 工程师,然后回复你这是为什么! (如果他们知道:p)
【讨论】:
在控制台应用程序中的结果也是一样的,我更新了示例以显示每个项目调用两次的是println
@mythz 啊,你是对的,我的回答不正确。让我深入研究一下
@mythz 我知道您是对的,因为如果您在前一个下方添加另一个 println
,则输出为 AABBCCAABBCC
奇怪的是,如果你总是return false
,它每次只运行一次以上是关于为啥 Swift 中的过滤器会迭代集合两次?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Swift 的 AVPlayer 一次播放会加载 playerItem 两次?