我的数组中有大约2000个元素,当它被过滤时,我想在我的过滤数组中有5个元素后立即结束过滤.
目前它是:
providerArray.filter({($0.lowercased().range(of:((row.value as? String)?.lowercased())!) != nil)})
这可以返回高达2000的结果,这是浪费处理和时间.
为了更清楚,我需要一个解决方案,相当于限制过滤器结果,就像我可以使用coreData提取 [request setFetchLimit: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: { $0 % 3 == 0 }, limit: 5) print(result) // [0, 3, 6, 9, 12]
你可以使用.lazy
太多提升性能:
let numbers: [Int] = Array(0 ..< 2000) let result: AnySequence = numbers .lazy .filter { print("Calling filter for: \($0)") return ($0 % 3) == 0 } .prefix(5) print(Array(result))
这将filter
仅为前15个值调用该函数(直到它找到5个通过过滤器的值).
现在你可以集中精力提升filter
自身的表现.例如通过缓存值.您不必这样做,但如果某些值不断重复,它可以大大提高性能.
let numbers: [Int] = Array(0 ..< 2000) var filterCache: [Int: Bool] = [:] let result: AnySequence = numbers .lazy .filter { if let cachedResult = filterCache[$0] { return cachedResult } print("Calling filter for: \($0)") let result = (($0 % 3) == 0) filterCache[$0] = result return result } .prefix(5) print(Array(result))
您可以将此方法直接应用于您的函数.
另请注意,为了提高性能,您应该:
保存((row.value as? String)?.lowercased())!
到局部变量,因为它被执行多次
使用选项简化表达式:
let result: AnySequence = providerArray .lazy .filter { $0.range(of: row.value as! String, options: [.caseInsensitive]) != nil } .prefix(5)