修改参数值时使用 filter{where:} 与 removeAll{where:} 的效率

K M*_*K M 5 swift swift4.2

Swift 4.2 引入了一个新的removeAll {where:} 函数。根据我的阅读,它应该比使用过滤器 {where:} 更有效。我的代码中有几个场景,如下所示:

private func getListOfNullDates(list: [MyObject]) -> [MyObject] {
        return list.filter{ $0.date == nil }
            .sorted { $0.account?.name < $1.account?.name }
    }
Run Code Online (Sandbox Code Playgroud)

但是,我不能将 removeAll{where:} 与参数一起使用,因为它是一个常量。所以我需要像这样重新定义它:

private func getListOfNullDates(list: [MyObject]) -> [MyObject] {
        var list = list
        list.removeAll { $0.date == nil }
        return list.sorted { $0.account?.name < $1.account?.name }
    }
Run Code Online (Sandbox Code Playgroud)

在这种情况下使用 removeAll 函数是否仍然更有效?还是坚持使用过滤功能更好?

iel*_*ani 5

谢谢你提出这个问题

我在 TIO 上使用此代码对这两个函数进行了基准测试:

let array = Array(0..<10_000_000)

do {
    let start = Date()
    let filtering = array.filter { $0 % 2 == 0 }
    let end = Date()

    print(filtering.count, filtering.last!, end.timeIntervalSince(start))
}

do {
    let start = Date()
    var removing = array
    removing.removeAll { $0 % 2 == 0 }
    let end = Date()

    print(removing.count, removing.last!, end.timeIntervalSince(start))
}
Run Code Online (Sandbox Code Playgroud)

(为了使removingfiltering相同,传递给的闭包removeAll应该是{ $0 % 2 != 0 },但我不想通过使用更快或更慢的比较运算符来给任一片段带来优势。)

事实上,removeAll(where:)当删除元素(我们称之为Pr)的概率为 50% 时,速度会更快!以下是基准测试结果:

filter    : 94ms
removeAll : 74ms
Run Code Online (Sandbox Code Playgroud)

Pr 当小于 50%时,情况也是如此。

否则,对于更高的 .过滤速度会更快Pr

需要记住的一件事是,您的代码list是可变的,这可能会导致意外修改。

就我个人而言,我会选择性能而不是旧习惯,从某种意义上说,这个用例更具可读性,因为意图更清晰。


奖励:就地移除

就地删除的意思是交换数组中的元素,以便将要删除的元素放置在某个枢轴索引之后。要保留的元素是主元元素之前的元素:

var inPlace = array
let p = inPlace.partition { $0 % 2 == 0 } 
Run Code Online (Sandbox Code Playgroud)

请记住,这partition(by:)不会保留原始顺序。

这种方法的时钟removeAll(where:)