Группировка списка кортежей Python
У меня есть список (метка, количество) кортежей, как это:
[('grape', 100), ('grape', 3), ('apple', 15), ('apple', 10), ('apple', 4), ('banana', 3)]
После этого я хочу суммировать все значения с одной и той же меткой (одни и те же метки всегда соседние) и вернуть список в том же порядке меток:
[('grape', 103), ('apple', 29), ('banana', 3)]
Я знаю, что мог бы решить это с чем-то вроде:
def group(l):
result = []
if l:
this_label = l[0][0]
this_count = 0
for label, count in l:
if label != this_label:
result.append((this_label, this_count))
this_label = label
this_count = 0
this_count += count
result.append((this_label, this_count))
return result
Но есть ли более Pythonic / элегантный / эффективный способ сделать это?
8 ответов
itertools.groupby
можете делать что хотите:
import itertools
import operator
L = [('grape', 100), ('grape', 3), ('apple', 15), ('apple', 10),
('apple', 4), ('banana', 3)]
def accumulate(l):
it = itertools.groupby(l, operator.itemgetter(0))
for key, subiter in it:
yield key, sum(item[1] for item in subiter)
>>> print list(accumulate(L))
[('grape', 103), ('apple', 29), ('banana', 3)]
>>>
Использование itertools и списочных представлений
import itertools
[(key, sum(num for _, num in value))
for key, value in itertools.groupby(l, lambda x: x[0])]
Изменить: как указал Гнибблер: если l
не отсортировано замените его sorted(l)
,
import collections
d=collections.defaultdict(int)
a=[]
alist=[('grape', 100), ('banana', 3), ('apple', 10), ('apple', 4), ('grape', 3), ('apple', 15)]
for fruit,number in alist:
if not fruit in a: a.append(fruit)
d[fruit]+=number
for f in a:
print (f,d[f])
выход
$ ./python.py
('grape', 103)
('banana', 3)
('apple', 29)
>>> from itertools import groupby
>>> from operator import itemgetter
>>> L=[('grape', 100), ('grape', 3), ('apple', 15), ('apple', 10), ('apple', 4), ('banana', 3)]
>>> [(x,sum(map(itemgetter(1),y))) for x,y in groupby(L, itemgetter(0))]
[('grape', 103), ('apple', 29), ('banana', 3)]
Моя версия без itertools [(k, sum([y for (x,y) in l if x == k])) for k in dict(l).keys()]
Метод
def group_by(my_list):
result = {}
for k, v in my_list:
result[k] = v if k not in result else result[k] + v
return result
использование
my_list = [
('grape', 100), ('grape', 3), ('apple', 15),
('apple', 10), ('apple', 4), ('banana', 3)
]
group_by(my_list)
# Output: {'grape': 103, 'apple': 29, 'banana': 3}
Вы конвертировать в список кортежей, как list(group_by(my_list).items())
,
Более простой ответ без каких-либо сторонних библиотек:
dct={}
for key,value in alist:
if key not in dct:
dct[key]=value
else:
dct[key]+=value
Или более простой и понятный ответ (без itertools):
pairs = [('foo',1),('bar',2),('foo',2),('bar',3)]
def sum_pairs(pairs):
sums = {}
for pair in pairs:
sums.setdefault(pair[0], 0)
sums[pair[0]] += pair[1]
return sums.items()
print sum_pairs(pairs)