Создание Python defaultdict с использованием вложенного списка кортежей - PullRequest
0 голосов
/ 13 ноября 2018

Сценарий таков, что у меня есть двумерный список.Каждый элемент внутреннего списка является кортежем (ключ, пара значений).Ключ может повториться в списке.Я хочу на лету создать dict по умолчанию таким образом, чтобы, наконец, в словаре хранился ключ и суммарная сумма всех значений этого ключа из двумерного списка.

Чтобы поставить код:

listOfItems = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]
finalDict = defaultdict(int)
for eachItem in listOfItems:
    for key, val in eachItem:
        finalDict[key] += val
print(finalDict)

Это дает мне то, что я хочу: defaultdict(<class 'int'>, {'a': 7, 'b': 5, 'c': 0, 'd': 5}), но я ищу более «Pythonic» способ с использованием пониманий.Поэтому я попробовал следующее:

finalDict = defaultdict(int)
finalDict = {key : finalDict[key]+val for eachItem in listOfItems for key, val in eachItem}
print(finalDict)

Но вывод: {'a': 6, 'b': 2, 'c': 0, 'd': 5} Что я делаю не так?Или же при использовании понимания Словарь не создается и не изменяется на лету?

Ответы [ 4 ]

0 голосов
/ 09 декабря 2018

пытается использовать встроенные методы python вместо самостоятельного кодирования функциональности:

Длинное и объясненное решение

from itertools import chain, groupby
from operator import itemgetter

listOfItems = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]

# just flat the list of lists into 1 list..
flatten_list = chain(*listOfItems)

# get all elements grouped by the key, e.g 'a', 'b' etc..
first = itemgetter(0)
groupedByKey = groupby(sorted(flatten_list, key=first), key=first))

#sum
summed_by_key = ((k, sum(item[1] for item in tups_to_sum)) for k, tups_to_sum in groupedByKey)

# create a dict
d = dict(summed_by_key)

print(d) # {'a': 7, 'b': 5, 'c': 0, 'd': 5}

~ решение в одну строку

from itertools import chain, groupby
from operator import itemgetter

first = itemgetter(0)
d = dict((k, sum(item[1] for item in tups_to_sum)) for k, tups_to_sum in groupby(sorted(chain(*listOfItems), key=first), key=first))

print(d) # {'a': 7, 'b': 5, 'c': 0, 'd': 5}
0 голосов
/ 13 ноября 2018

Простое решение без использования дополнительных модулей:

inp_list = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]

l = [item for sublist in inp_list for item in sublist] # flatten the list

sums = [(key, sum([b for (a,b) in l if a == key])) for key in dict(l)]

print(sums)
0 голосов
/ 13 ноября 2018

Это потому, что вы не назначаете какое-либо значение для своего finalDict внутри вашего dict в понимании.

В своем понимании вы буквально меняете тип finalDict

Насколько я знаю, вы не можете присвоить значение своему диктату внутри диктата в понимании.

Вот способ получить нужный вам словарь

from functools import reduce

listOfItems = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]

list_dict = [{key: val} for eachItem in listOfItems for key, val in eachItem]

def sum_dict(x, y):
    return {k: x.get(k, 0) + y.get(k, 0) for k in set(x) | set(y)}
print(reduce(sum_dict, list_dict))
0 голосов
/ 13 ноября 2018

Да, понимание не может быть обновлено на лету. В любом случае, эта задача может лучше подходить для collections.Counter() с .update() вызовами:

>>> from collections import Counter
>>> c = Counter()
>>> for eachItem in listOfItems:
...     c.update(dict(eachItem))
... 
>>> c
Counter({'a': 7, 'b': 5, 'd': 5, 'c': 0})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...