在Python中进行列表/字典理解时是否可以访问当前对象?

问题描述 投票:0回答:4

我正在尝试想出一种单行代码来实现以下目标(对键的所有值求和):

>>> data = [('a', 1), ('b', 3), ('a', 4), ('c', 9), ('b', 1), ('d', 3)]
>>> res = {}
>>> for tup in data:
...     res[tup[0]] = res.setdefault(tup[0], 0) + tup[1]
... 
>>> res
{'a': 5, 'c': 9, 'b': 4, 'd': 3}

单行版本,不使用任何导入,如 itertools、集合等。

 {tup[0]: SELF_REFERENCE.setdefault(tup[0], 0) + tup[1]  for tup in data}

Python 中是否可以使用当前正在理解的对象的引用?

如果没有,有没有什么方法可以在不使用任何导入的情况下以单行实现这一点,即使用基本的列表/字典理解和内置函数?

python list-comprehension dictionary-comprehension
4个回答
12
投票

不,没有。字典理解会为每次迭代生成一个new项目,并且您的代码需要生成较少项目(合并值)。

如果不使用(丑陋的、非Pythonic的)副作用技巧,就无法访问早期迭代中生成的密钥。理解将要生成的

dict
对象尚不存在,因此也无法生成自引用。

只需坚持你的

for
循环,它的可读性要强得多。

另一种方法是使用排序和分组,O(NlogN) 算法与直接循环的简单 O(N) 算法:

from itertools import groupby
from operator import itemgetter

res = {key: sum(t[1] for t in group) 
       for key, group in groupby(sorted(data, key=itemgetter(0)), key=itemgetter(0))}

2
投票

使用

reduce
collections.Counter
:

>>> from operator import add
>>> from collections import Counter
>>> reduce(add, (Counter(dict([x])) for x in data))
Counter({'c': 9, 'a': 5, 'b': 4, 'd': 3})

2
投票

请勿使用眼线笔。相反,使用

collections.defaultdict
和一个简单的 for 循环:

>>> pairs = [('a', 1), ('b', 3), ('a', 4), ('c', 9), ('b', 1), ('d', 3)]
>>> result = defaultdict(int)
>>> for key, value in pairs:
...     result[key] += value
...
>>> result
defaultdict(<class 'int'>, {'a': 5, 'c': 9, 'b': 4, 'd': 3})

它很容易理解,Pythonic且快速。


2
投票

这几乎就像您正在尝试做的事情。但我不会推荐这个,因为可读性会受到影响。

data = [('a',1),('b',3),('a',4),('c',9),('b',1),('d',3)]
print reduce(lambda d,i: [d.__setitem__(i[0],d.get(i[0],0)+i[1]),d][1], data, {})

输出

{'a': 5, 'c': 9, 'b': 4, 'd': 3}
© www.soinside.com 2019 - 2024. All rights reserved.