将Swift数组筛选器的结果限制为X以提高性能

我在我的数组中有大约2000个元素,当它被过滤时,我希望在过滤数组中有5个元素时立即结束过滤。

目前它是:

providerArray.filter({($0.lowercased().range(of:((row.value as? String)?.lowercased())!) != nil)}) 

最多可以返回2000个结果,浪费了处理时间。

更清楚的是,我需要一个解决scheme,相当于像coreData fetches [request setFetchLimit:5];一样限制过滤结果[request setFetchLimit:5];

就执行时间而言,最快的解决scheme似乎是一个明确的循环,它添加了匹配元素,直到达到极限:

 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)) 

这将只为前15个值调用filter函数(直到find5个通过filter)。

现在,您可以专注于提高filter本身的性能。 例如通过caching值。 你不必这样做,但如果一些价值观不断重复,它可以提高性能很多。

 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)) 

您可以将此方法直接应用于您的function。

另外请注意,要提高性能,您应该:

  • 保存((row.value as? String)?.lowercased())! 变成一个局部variables,因为它被执行多次

  • 使用选项简化expression式:

  let result: AnySequence = providerArray .lazy .filter { $0.range(of: row.value as! String, options: [.caseInsensitive]) != nil } .prefix(5)