Is it possible to access current object while doing list/dict comprehension in Python?

情到浓时终转凉″ 提交于 2019-11-26 11:38:56

问题


Trying to think of a one-liner to achieve the following ( summing all the values of a key) :

>>> 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}

One-liner version without using any imports like itertools,collections etc.

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

Is it possible in Python to use a reference to the object currently being comprehended ? If not, is there any way to achieve this in a one-liner without using any imports i.e. using basic list/dict comprehension and inbuilt functions.


回答1:


No, there is not. A dict comprehension produces a new item for each iteration, and your code needs to produce fewer items (consolidating values).

There is no way to access keys produced in an earlier iteration, not without using (ugly, unpythonic) side-effect tricks. The dict object that is going to be produced by the comprehension doesn't exist yet, so there is no way to produce a self-reference either.

Just stick to your for loop, it is far more readable.

The alternative would be to use sorting and grouping, a O(NlogN) algorithm vs. the simple O(N) of your straight loop:

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:


Don't use a oneliner. Instead use collections.defaultdict and a simple for loop:

>>> 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})

It is easy to understand, pythonic and fast.




回答3:


Use reduce and 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})



回答4:


This is almost like, what you are trying to do. But I won't recommend this, as the readability suffers.

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, {})

Output

{'a': 5, 'c': 9, 'b': 4, 'd': 3}


来源:https://stackoverflow.com/questions/21112814/is-it-possible-to-access-current-object-while-doing-list-dict-comprehension-in-p

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!