通过dict理解增加dict值

时间:2018-09-19 23:25:13

标签: python python-3.x ternary dictionary-comprehension

我正在尝试使用dict理解和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循环的功能不同吗?谢谢。

3 个答案:

答案 0 :(得分:2)

不要。 似乎就像使用dict理解那样,应该是一个好主意,但这实际上是一个可怕的陷阱。使用collections.Counter

import counts

seen_dict = collections.Counter(ar)

或者如果您不想这样做,那么请坚持循环。

尝试使用dict理解的问题是dict理解没有很好的方法来维持状态或交错每个键的值的计算。每个值必须在单个表达式中计算。相反,解决计数问题的最佳方法是对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)。

如果我们使用输入list(range(10000)) run a timing中的这四个摘要:

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版本的运行时间似乎较低,这是由于某种首次运行效果会降低其他版本的运行速度;交换set和非set版本的顺序通常会相反set的重复数据删除在此测试中无济于事,因为输入没有重复。)

对于更长的输入,依赖count的代价甚至更高。依靠count可以很容易地花费几天时间,而Counter仍会在一秒钟之内完成。

答案 1 :(得分:1)

在这里,它实际上比我想象的要简单。基本上,您想要的是列表中某事物发生的次数,您可以通过说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}

答案 2 :(得分:-1)

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

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

说明:

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

字典返回的键值对为number-# of appearances of number in arr