通过字典理解增加字典值

Incrementing dict values with dict comprehension

我正在尝试使用字典理解和 python 中的三元运算来执行以下表达式:

for num in ar:
     if num in seen_dict:
         seen_dict[num] += 1
     else:
         seen_dict[num] = 1

我试过这个:

seen_dict = { num: seen_dict[num] += 1 for num in ar if num in seen_dict else seen_dict[num] = 1}

及其几个排列,但我不断收到语法错误。是否可以如我所愿?

更新

这是正确的语法,但不是我的字典只返回 1: seen_dict = { num: (seen_dict[num] + 1) if num in seen_dict else 1 for num in ar }

有人可以解释为什么这与 for 循环的功能不同吗?谢谢。

到这里,其实比我想象的要简单的多。基本上你想要的是列表中某事出现的次数,你可以说 ar.count(num)。你可以很容易地做到这一点而无需像这样的三元运算符:

ar = [1,2,3,2]
seen_dict = { num:ar.count(num) for num in ar}
print(seen_dict)# {1:1, 2:2, 3:1}

您似乎在尝试获取列表中所有值的出现。 (如果不是,请告诉我。)以下是我的处理方法:

seen_dict = {num: arr.count(num) for num in list(set(arr))}

一个解释:

  • arr.count(num)list.count(element)方法returns elementlist
  • 中出现的次数
  • set(arr):创建一个 set 对象,当转换回列表时删除所有重复项,或者换句话说,获取列表的所有不同值
  • list(set(arr))arr
  • 中的不同值

字典 return 的键值对为 number-# of appearances of number in arr.

不要。 似乎 像使用 dict comprehensions 这样应该是个好主意,但它实际上是一个可怕的陷阱。使用 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 这四个片段的输入 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 片段都需要一秒钟。 (set 版本似乎有一个较短的 运行 时间,因为某种 first-运行 效应减慢了另一个版本;交换 set 和非-set version 通常会反转这些版本的相对时间。set 的重复数据删除在这个测试中没有帮助,因为输入没有重复项。)

对于更长的输入,依赖 count 会更加昂贵。依靠 count 很容易花费数天的时间来输入 Counter 仍然会在一秒钟内完成。