当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《将Swift数组过滤器的结果限制为X以获得性能》经验,为你挑选了2个好方法。

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

目前它是:

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

这可以返回高达2000的结果,这是浪费处理和时间.

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



1> Martin R..:

就执行时间而言,最快的解决方案似乎是一个显式循环,它会在达到限制之前添加匹配元素:

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]



2> Sulthan..:

你可以使用.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)


如果你将`result`注释为`AnySequence`,那么每个元素只调用一次`filter`的谓词(那么你可以取消缓存).这是因为`前缀(_ :)`默认情况下它会输出一个切片,首先需要索引延迟集合,该集合必须通过过滤器运行,然后再次运行`Array(_ :)`初始化程序.虽然为什么它第三次被运行,但我不太确定.
甚至`print(results.first!)`在打印第一个元素之前遍历索引0 ... 15,0 ... 3.@Hamish显然有解释,但行为可能是出乎意料的,解决方案并不明显(至少对我不起). - 顺便说一句,`让结果= numbers.makeIterator().lazy.filter ......`也可以.
@MartinR是的,那是因为`prefix(5)`(在输出切片的情况下)需要将索引提升到过滤结果中的第5个元素,从而通过索引0 ... 15.`first`然后必须遍历0 ... 3才能从过滤后的结果中找到第一个:)我打算在今天晚些时候对此进行调查,并且可能会发布一个详细解释它的问答,因为我同意这个行为是一点也不明显.
推荐阅读
有风吹过best
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有