首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用dict理解递增dict值

用dict理解递增dict值
EN

Stack Overflow用户
提问于 2018-09-19 23:25:12
回答 3查看 2.6K关注 0票数 0

我试图在python中使用dict理解和三元操作来完成以下表达式:

代码语言:javascript
复制
for num in ar:
     if num in seen_dict:
         seen_dict[num] += 1
     else:
         seen_dict[num] = 1

我试过这个:

代码语言:javascript
复制
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循环那样起作用吗?谢谢。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-09-19 23:52:37

不要。这似乎是一个好主意,但它实际上是一个可怕的陷阱。使用collections.Counter

代码语言:javascript
复制
import counts

seen_dict = collections.Counter(ar)

或者,如果你不想这样做,那就坚持循环。

尝试使用dict理解的问题是,dict理解没有很好的方法来维护状态或交错计算每个键的值。每个值必须在一个表达式中计算。相反,解决计数问题的最佳方法是对ar进行一次传递,并在执行过程中更新每个元素的计数。

对理解的限制导致了极其低效的尝试,比如

代码语言:javascript
复制
seen_dict = {val: ar.count(val) for val in ar}

这使得通过ar的次数等于ar的长度,或者稍微更有效,但仍然是可怕的次优。

代码语言:javascript
复制
seen_dict = {val: ar.count(val) for val in set(ar)}

它只需要通过len(set(ar)),或者对于对标准库更熟悉一点

代码语言:javascript
复制
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))

代码语言:javascript
复制
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()))

我们得到以下输出:

代码语言:javascript
复制
0.0005530156195163727
1.0503493696451187
1.0463058911263943
0.00422721728682518

Counter在半毫秒内完成,而count代码段都占用了一秒时间。(由于某种第一次运行效果,set版本的运行时似乎更低;交换set和非set版本的顺序通常会逆转这些版本的相对时间。set的重复对这个测试没有帮助,因为输入没有重复。)

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

票数 5
EN

Stack Overflow用户

发布于 2018-09-19 23:38:48

在这里,它实际上比我想象的要简单得多。基本上,您想要的是列表中发生的事情发生的次数,这可以通过ar.count(num)来完成。您可以很容易地做到这一点,不需要像这样的三元操作符:

代码语言:javascript
复制
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
EN

Stack Overflow用户

发布于 2018-09-19 23:38:57

似乎你在试图在一个列表中得到所有值的表象。(如果不是,请告诉我。)以下是我处理这个问题的方法:

代码语言:javascript
复制
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的键值对。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52415446

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档