将Swift数组过滤器的结果限制为X以获得性能

时间:2017-01-26 10:51:32

标签: ios swift nspredicate

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

目前是:

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

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

为了更清楚,我需要一个解决方案,相当于限制过滤器结果,就像我可以使用coreData提取[request setFetchLimit:5];

2 个答案:

答案 0 :(得分:7)

在执行时间方面最快的解决方案似乎是 显式循环,它会添加匹配元素,直到达到限制:

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]

答案 1 :(得分:5)

您可以使用.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函数(直到它找到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)