我看到一个答案到了这个问题,它在它的第一个版本,也有类似的代码如下:
let numbers = Array(0 ..< 50)
let result = numbers.lazy
.filter {
// gets called 2-3x per element in the range (0...15)!
print("Calling filter for: \($0)")
return $0 % 3 == 0
}
.prefix(5)
print(Array(result)) // [0, 3, 6, 9, 12]
Run Code Online (Sandbox Code Playgroud)
通过使用惰性过滤器集合,它能够过滤numbers满足给定谓词的前5个元素(在这种情况下,可被3整除),而无需评估数组中的每个元素numbers.
然而,答案然后指出,filter(_:)每个元素可以多次调用谓词(范围1 ... 15中的元素为3次,结果为0时为2).
这种过滤器的惰性评估效率低下的原因是什么?有没有办法避免多次评估同一元素?
每隔一段时间,我必须沿着响应者链向上走才能到达已知类的实例。(只是为了这个问题接受这个。)我一直在用一个 while 循环来做这个,但我突然想到使用它会更酷sequence(),它可以像这样巧妙地表达响应者链本身:
let chain = sequence(first: someView as UIResponder) {$0.next}
Run Code Online (Sandbox Code Playgroud)
这太棒了,因为到目前为止我们还没有真正走路;序列是惰性的,在我们开始请求元素之前不会执行匿名函数。为了证明这一点,让我用打印语句检测该代码:
let chain = sequence(first: someView as UIResponder) {r in print(r); return r.next}
Run Code Online (Sandbox Code Playgroud)
好的,假设我正在寻找链中的第一个 ViewController 实例。我可以这样找到它:
if let vc = (chain.first {$0 is ViewController}) as? ViewController {
print(vc)
}
Run Code Online (Sandbox Code Playgroud)
打印输出显示惰性仍然存在:我们沿着响应者链向上走,直到到达 ViewController 并停止。完美的!在花括号内,vc输入为 ViewController,我们就开始比赛了。
然而,它不会逃脱你的注意,那是丑陋的。我正在测试和铸造。有没有一种方法可以让我在不测试的情况下进行转换并且仍然以 ViewController 结束?
这是优雅的,它工作正常:
for case let vc as ViewController in chain {
print(vc)
break
}
Run Code Online (Sandbox Code Playgroud)
这很可爱,而且保持着懒惰——但我必须记得break在最后说,这会毁了一切。
好吧,当我想到这一点时,我真的充满希望:
if let vc = (chain.compactMap{ $0 as? ViewController }.first) {
print(vc)
} …Run Code Online (Sandbox Code Playgroud)