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

时间:2019-04-09 18:15:15

标签: swift swift4.2

Swift 4.2引入了新的removeAll {where:} function。据我了解,它应该比使用过滤器{where:}更有效。我的代码中有以下几种情况:

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

但是,我不能将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 }
    }

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

2 个答案:

答案 0 :(得分:2)

提防过早的优化。方法的效率通常取决于您的特定数据和配置,除非您使用大型数据集或一次执行许多操作,否则这两种方法都不会产生重大影响。除非这样做,否则您应该支持更具可读性和可维护性的解决方案。

作为一般规则,当您想对原始数组进行突变时,只需使用removeAll,否则就可以使用filter。如果您已将其识别为程序中的潜在瓶颈,请然后对其进行测试,以查看是否存在性能差异。

答案 1 :(得分:1)

谢谢您这个问题

我已经在TIO上使用以下代码benchmarked了:

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

(要使removingfiltering相同,传递给removeAll的闭包应该是{ $0 % 2 != 0 },但我不想给两者中的任何一个带来好处使用比较快或慢的比较运算符的摘要。)

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

filter    : 94ms
removeAll : 74ms

Pr is less than 50%时也是这种情况。

否则,过滤is faster以获得更高的Pr

要记住的一件事是,代码list中的变量是可变的,这为意外修改提供了可能。

就个人而言,我会选择性能而不是老习惯,并且从某种意义上讲,此用例更具可读性,因为其意图更加明确。


奖金:就地删除

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

var inPlace = array
let p = inPlace.partition { $0 % 2 == 0 } 

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

这种方法clocksremoveAll(where:)更好