Это кажется трудным для достижения с помощью reduce
, потому что если оба кортежа, которые вы «сокращаете», не имеют одной и той же буквы, вы не можете вычислить результат. Как уменьшить ('a',1)
и ('b',1)
до какого-то жизнеспособного результата?
Лучшее, что я мог сделать, это l = functools.reduce(lambda x,y : (x[0],x[1]+y[1]) if x[0]==y[0] else x+y,sorted(l))
меня это достало ('a', 3, 'b', 1, 'c', 1, 'c', 1)
. Таким образом, для первого элемента это сработало, но для остальных потребовалось бы больше одного прохода (воссоздание кортежей и создание другого аналогичного reduce
, мягко говоря, не очень эффективно!).
Во всяком случае, вот 2 рабочих способа сделать это
Во-первых, используя collections.Counter
подсчет элементов одного типа:
l = [('a', 1), ('a', 1), ('b', 1), ('c',1), ('a', 1), ('c', 1)]
import collections
c = collections.Counter()
for a,i in l:
c[a] += i
Мы не можем использовать listcomp, потому что каждый элемент имеет вес (даже если здесь он равен 1).
Результат: словарь: Counter({'a': 3, 'c': 2, 'b': 1})
Второй вариант: используйте itertools.groupby
в отсортированном списке, группируя по имени/букве и выполняя сумму целых чисел, имеющих одну и ту же букву:
print ([(k,sum(e for _,e in v)) for k,v in itertools.groupby(sorted(l),key=lambda x : x[0])])
результат:
[('a', 3), ('b', 1), ('c', 2)]
person
Jean-François Fabre
schedule
02.04.2017