私はこのような(ラベル、カウント)タプルのリストを持っています:
[('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 /エレガント/効率的な方法はありますか?
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])]
_
編集: gnibblerが指摘したように: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())
のようなタプルのリストに変換します。
または、より単純で読みやすい回答(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)