不要。 似乎为此使用 dict 理解应该是一个好主意,但它实际上是一个可怕的陷阱。使用collections.Counter:
import counts
seen_dict = collections.Counter(ar)
或者如果你不想这样做,那就坚持循环。
尝试使用字典推导的问题在于字典推导没有好的方法来维护状态或交错计算每个键的值。每个值都必须在单个表达式中计算。相比之下,解决计数问题的最佳方法是对ar 进行一次遍历,并随时更新每个元素的计数。
理解的限制会导致非常低效的尝试,例如
seen_dict = {val: ar.count(val) for val in ar}
这使得通过ar 的次数等于ar 的长度,或者效率稍高但仍然非常不理想
seen_dict = {val: ar.count(val) for val in set(ar)}
只需要让len(set(ar))通行证,或者为人a bit more familiar with the standard library,
from itertools import groupby
seen_dict = {val: sum(1 for _ in group) for val, group in groupby(sorted(ar))}
这至少不是二次时间,但对于长度为 n 的 ar 仍然是 O(nlogn)。
如果我们 run a timing 这四个 sn-ps 输入 list(range(10000)):
from collections import Counter
from itertools import groupby
from timeit import timeit
ar = list(range(10000))
print(timeit('Counter(ar)', number=1, globals=globals()))
print(timeit('{val: ar.count(val) for val in ar}', number=1, globals=globals()))
print(timeit('{val: ar.count(val) for val in set(ar)}', number=1, globals=globals()))
print(timeit('{val: sum(1 for _ in group) for val, group in groupby(sorted(ar))}',
number=1, globals=globals()))
我们得到以下输出:
0.0005530156195163727
1.0503493696451187
1.0463058911263943
0.00422721728682518
Counter 在半毫秒内完成,而count sn-ps 都需要一秒钟。 (set 版本似乎具有较低的运行时间,因为某种首次运行效果会减慢另一个版本的速度;交换set 和非set 版本的顺序通常会颠倒这些版本的相对时间. set 的重复数据删除对这个测试没有帮助,因为输入没有重复。)
对于更长的输入,依赖count 将更加昂贵。依靠count 很容易花费几天的时间来输入Counter 仍然会在一秒钟内完成。