Слияние части кортежей в Python

58
8

У меня несколько сотен кортежей в следующем формате (id1, id2, id3, [xydata]) Например:

('a', 'b', 'c', [(1, 2),(2, 3),(3, 4)])
('a', 'b', 'c', [(1, 1),(2, 4),(3, 6)])
('a', 'b', 'd', [(1, 3),(2, 6),(3, 7)])
('a', 'b', 'd', [(1, 7),(2, 8),(3, 9)])

Теперь я хочу объединить кортежи, чтобы те, которые начинаются с тех же трех значений, объединяются следующим образом. Я уверен, что те же самые значения X находятся во всех xydata:

('a', 'b', 'c', [(1, mean(2, 1)),(2, mean(3, 4)),(3, mean(4, 6))])
('a', 'b', 'd', [(1, mean(3, 7)),(2, mean(6, 8)),(3, mean(7, 9))])

Текущее решение выполняет несколько шагов, чтобы переупорядочить и разбить данные, сохраняя кортежи в многослойном словаре, прежде чем объединять их и восстанавливать исходную структуру данных. Есть ли опрятный и Pythonic способ сделать это вместо этого?

спросил(а) 2014-03-06T19:01:00+04:00 6 лет, 6 месяцев назад
1
Решение
57

Вы можете объединиться, используя defaultdict:

>>> l = [('a', 'b', 'c', [(1, 2),(2, 3),(3, 4)]),
... ('a', 'b', 'c', [(1, 1),(2, 4),(3, 6)]),
... ('a', 'b', 'd', [(1, 3),(2, 6),(3, 7)]),
... ('a', 'b', 'd', [(1, 7),(2, 8),(3, 9)])]

>>> d = defaultdict(lambda:defaultdict(list))
>>> for k1,k2,k3, lst in l:
... for t in lst:
... d[(k1,k2,k3)][t[0]].append(t[1])

результат:

>>> d
defaultdict(<function <lambda> at 0x8e33e9c>,
{('a', 'b', 'c'): defaultdict(<type 'list'>, {1: [2, 1], 2: [3, 4], 3: [4, 6]}),
('a', 'b', 'd'): defaultdict(<type 'list'>, {1: [3, 7], 2: [6, 8], 3: [7, 9]})})

если вам это нужно в списке:

>>> [(k, v.items()) for k,v in d.items()]
[(('a', 'b', 'c'), [(1, [2, 1]), (2, [3, 4]), (3, [4, 6])]),
(('a', 'b', 'd'), [(1, [3, 7]), (2, [6, 8]), (3, [7, 9])])]

со средним расчетом:

>>> [(k, [(n, sum(t)/float(len(t))) for n,t in v.items()]) for k,v in d.items()]
[(('a', 'b', 'c'), [(1, 1.5), (2, 3.5), (3, 5.0)]),
(('a', 'b', 'd'), [(1, 5.0), (2, 7.0), (3, 8.0)])]

ответил(а) 2014-03-06T19:30:00+04:00 6 лет, 6 месяцев назад
69

Использование itertools.groupby, izip и некоторых списков:

from itertools import groupby, izip
from pprint import pprint

lis = [('a', 'b', 'c', [(1, 2), (2, 3), (3, 4)]), ('a', 'b', 'c', [(1, 1), (2, 4), (3, 6)]), ('a', 'b', 'd', [(1, 3), (2, 6), (3, 7)]), ('a', 'b', 'd', [(1, 7), (2, 8), (3, 9)])]

def solve(seq, X):
for k, g in groupby(seq, key=lambda x:x[:3]):
data = ((y[1] for y in x[3]) for x in g)
yield tuple(list(k) + [[(a, sum(b, 0.0)/len(b))
for a, b in izip(X, izip(*data))]])

X = [a for a, _ in lis[0][3]]
pprint(list(solve(lis, X)))


Вывод:

[('a', 'b', 'c', [(1, 1.5), (2, 3.5), (3, 5.0)]),
('a', 'b', 'd', [(1, 5.0), (2, 7.0), (3, 8.0)])]

ответил(а) 2014-03-06T19:30:00+04:00 6 лет, 6 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема