将 Swift 数组过滤器的结果限制为 X 以提高性能
Limit the results of a Swift array filter to X for performance
我的数组中有大约 2000 个元素,当它被过滤时,我想在我的过滤数组中有 5 个元素时立即结束过滤。
目前是:
providerArray.filter({([=11=].lowercased().range(of:((row.value as? String)?.lowercased())!) != nil)})
最多可以 return 2000 个结果,这是浪费处理和时间。
为了更清楚,我需要一个解决方案,该解决方案相当于限制过滤结果,就像我可以使用 coreData 提取一样 [request setFetchLimit:5];
您也可以使用 .lazy
来稍微提高性能:
let numbers: [Int] = Array(0 ..< 2000)
let result: AnySequence = numbers
.lazy
.filter {
print("Calling filter for: \([=10=])")
return ([=10=] % 3) == 0
}
.prefix(5)
print(Array(result))
这将只为前 15 个值调用 filter
函数(直到它找到 5 个通过过滤器)。
现在您可以专注于提高 filter
本身的性能。例如。通过缓存值。您不必这样做,但如果某些值不断重复,它可以大大提高性能。
let numbers: [Int] = Array(0 ..< 2000)
var filterCache: [Int: Bool] = [:]
let result: AnySequence = numbers
.lazy
.filter {
if let cachedResult = filterCache[[=11=]] {
return cachedResult
}
print("Calling filter for: \([=11=])")
let result = (([=11=] % 3) == 0)
filterCache[[=11=]] = result
return result
}
.prefix(5)
print(Array(result))
您可以将此方法直接应用于您的函数。
另请注意,要提高性能,您应该:
保存((row.value as? String)?.lowercased())!
到一个局部变量中因为执行了多次
使用选项简化表达式:
let result: AnySequence = providerArray
.lazy
.filter {
[=12=].range(of: row.value as! String, options: [.caseInsensitive]) != nil
}
.prefix(5)
就执行时间而言最快的解决方案似乎是
添加匹配元素直到达到限制的显式循环:
extension Sequence {
public func filter(where isIncluded: (Iterator.Element) -> Bool, limit: Int) -> [Iterator.Element] {
var result : [Iterator.Element] = []
result.reserveCapacity(limit)
var count = 0
var it = makeIterator()
// While limit not reached and there are more elements ...
while count < limit, let element = it.next() {
if isIncluded(element) {
result.append(element)
count += 1
}
}
return result
}
}
用法示例:
let numbers = Array(0 ..< 2000)
let result = numbers.filter(where: { [=11=] % 3 == 0 }, limit: 5)
print(result) // [0, 3, 6, 9, 12]
我的数组中有大约 2000 个元素,当它被过滤时,我想在我的过滤数组中有 5 个元素时立即结束过滤。
目前是:
providerArray.filter({([=11=].lowercased().range(of:((row.value as? String)?.lowercased())!) != nil)})
最多可以 return 2000 个结果,这是浪费处理和时间。
为了更清楚,我需要一个解决方案,该解决方案相当于限制过滤结果,就像我可以使用 coreData 提取一样 [request setFetchLimit:5];
您也可以使用 .lazy
来稍微提高性能:
let numbers: [Int] = Array(0 ..< 2000)
let result: AnySequence = numbers
.lazy
.filter {
print("Calling filter for: \([=10=])")
return ([=10=] % 3) == 0
}
.prefix(5)
print(Array(result))
这将只为前 15 个值调用 filter
函数(直到它找到 5 个通过过滤器)。
现在您可以专注于提高 filter
本身的性能。例如。通过缓存值。您不必这样做,但如果某些值不断重复,它可以大大提高性能。
let numbers: [Int] = Array(0 ..< 2000)
var filterCache: [Int: Bool] = [:]
let result: AnySequence = numbers
.lazy
.filter {
if let cachedResult = filterCache[[=11=]] {
return cachedResult
}
print("Calling filter for: \([=11=])")
let result = (([=11=] % 3) == 0)
filterCache[[=11=]] = result
return result
}
.prefix(5)
print(Array(result))
您可以将此方法直接应用于您的函数。
另请注意,要提高性能,您应该:
保存
((row.value as? String)?.lowercased())!
到一个局部变量中因为执行了多次使用选项简化表达式:
let result: AnySequence = providerArray
.lazy
.filter {
[=12=].range(of: row.value as! String, options: [.caseInsensitive]) != nil
}
.prefix(5)
就执行时间而言最快的解决方案似乎是 添加匹配元素直到达到限制的显式循环:
extension Sequence {
public func filter(where isIncluded: (Iterator.Element) -> Bool, limit: Int) -> [Iterator.Element] {
var result : [Iterator.Element] = []
result.reserveCapacity(limit)
var count = 0
var it = makeIterator()
// While limit not reached and there are more elements ...
while count < limit, let element = it.next() {
if isIncluded(element) {
result.append(element)
count += 1
}
}
return result
}
}
用法示例:
let numbers = Array(0 ..< 2000)
let result = numbers.filter(where: { [=11=] % 3 == 0 }, limit: 5)
print(result) // [0, 3, 6, 9, 12]