【发布时间】:2017-07-11 19:12:38
【问题描述】:
后两种方案比前一种方案好在哪里?
primes = (1, 2, 3, 5, 7)
# Classic solution
items = list(range(10))
for prime in primes:
items.remove(prime)
items
# List comprehension
items = list(range(10))
[item for item in items if item not in primes]
# Filter
items = list(range(10))
list(filter(lambda item: item not in primes, items))
这三个例子是我在一本书中看到的,它说第一个解决方案需要 O(n*m) 时间 (n=len(items), m=len(primes)) 而后两个需要 O (n*1) time... 对第一个解决方案进行了 50 次比较(实际上稍微好一点 - 40 次比较),而后者只有 10 次。
我不明白这一点。我不明白它怎么会节省时间或内存。
这是书中解释这一点的段落:
要从列表中删除或插入单个项目,Python 需要复制 整个列表,对于较大的列表尤其重。执行时 这只是一次,当然不是那么糟糕。但是当执行一个大 删除的数量,过滤器或列表理解要快得多 解决方案,因为如果结构合理,它只需要复制列表 一次。 ....然后是例子... 对于大型项目列表,后两者要快得多。这是因为 操作要快得多。要使用 n=len(items) 和 m=len(primes) 进行比较, 第一个需要 O(m*n)=5*10=50 操作,而后两个需要 O(n*1)=10*1=10 次操作。
编辑:
书没有错。 primes = set((1, 2, 3, 5, 7)) 是正确的声明,而不是 primes = (1, 2, 3, 5, 7)
【问题讨论】:
-
在纸上解决就明白了。我们可能无法真正使它比代码更清晰。
-
所有解都是
O(n*m),因为线性搜索长度为mn次的素数列表。 -
@itachi 我认为这本书试图说 IN 是测试存在性的有效运算符。后两个 sn-ps 可以利用 IN,因此如果素数是一个 Set,则具有 O(n)。
-
你确定这本书没有将素数定义为一个集合吗?即
primes = {1, 2, 3, 5, 7}?只有在这样的情况下,该陈述才会为真。 -
这本书似乎暗示,由于
primes是一个简短的常量列表,它只是对 O() 有贡献的一个因素。另一方面,remove()是O(n),所以你有一个隐藏的嵌套循环。其他两种解决方案只有一个直循环。
标签: python list data-structures filter list-comprehension