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

前端 未结 4 1887
慢半拍i
慢半拍i 2020-11-30 14:21

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),(\'         


        
相关标签:
4条回答
  • 2020-11-30 14:45

    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.

    0 讨论(0)
  • 2020-11-30 14:51

    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))}
    
    0 讨论(0)
  • 2020-11-30 15:03

    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}
    
    0 讨论(0)
  • 2020-11-30 15:06

    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})
    
    0 讨论(0)
提交回复
热议问题