Преобразование списка кортежей во вложенный список с использованием Python - PullRequest
3 голосов
/ 06 декабря 2009

Я хочу преобразовать список кортежей во вложенный список, используя Python. Как мне это сделать?

У меня есть отсортированный список кортежей (отсортированный по второму значению):

[(1, 5),  (5, 4), (13, 3), (4, 3), (3, 2), (14, 1), (12, 1), 
 (10, 1), (9, 1), (8, 1),  (7, 1), (6, 1), (2, 1)]

Теперь я хочу, чтобы оно было таким (второе значение игнорируется и вкладывается в списки):

[ [1], [5], [13, 4], [3], [14, 12, 10, 9, 8, 7, 6, 2] ]

Я видел здесь другие темы с map, используемыми для таких вещей, но я не совсем понимаю это. Кто-нибудь может дать представление о «правильном» питонском способе сделать это?

Ответы [ 5 ]

11 голосов
/ 06 декабря 2009
from operator import itemgetter
from itertools import groupby

lst = [(1, 5),  (5, 4), (13, 3), (4, 3), (3, 2), (14, 1),
       (12, 1), (10, 1), (9, 1), (8, 1),  (7, 1), (6, 1), (2, 1)]

result = [[x for x, y in group]
          for key, group in groupby(lst, key=itemgetter(1))]

groupby(lst, key=itemgetter(1)) генерирует группы последовательных элементов из lst, в которых все элементы имеют одинаковый 1-й (считая с нуля) элемент. [x for x, y in group] сохраняет 0-й элемент каждого элемента в каждой группе.

2 голосов
/ 06 декабря 2009

Это немного запутанно, но вы можете сделать это с помощью функции itertools.groupby:

>>> lst = [(1, 5),  (5, 4), (13, 3), (4, 3), (3, 2), (14, 1), (12, 1), 
 (10, 1), (9, 1), (8, 1),  (7, 1), (6, 1), (2, 1)]
>>> from operator import itemgetter 
>>> import itertools
>>> [map(itemgetter(0), group) for (key,group) in itertools.groupby(lst, itemgetter(1))]
[[1], [5], [13, 4], [3], [14, 12, 10, 9, 8, 7, 6, 2]]
>>> 

Пояснение: groupby возвращает итератор для каждой группы, где группа определяется как последовательность записей, которые имеют одинаковое значение, возвращаемое функцией, передаваемой в качестве отдельного параметра. itemgetter (1) генерирует функцию, которая возвращает x [1] при вызове с аргументом x. Поскольку итератор groupby возвращает два значения - ключ, который использовался, и последовательности исходных значений, которые являются кортежами, нам необходимо выделить второе значение в каждом кортеже, что и делает map (itemgetter (0), group).

1 голос
/ 06 декабря 2009

Простое решение:

n_list = []
c_snd = None
for (fst, snd) in o_list:
  if snd == c_snd: n_list[-1].append(fst)
  else:
    c_snd = snd
    n_list.append([fst])

Объяснение: используйте c_snd для сохранения текущей второй части кортежа. Если это изменится, начните новый список в n_list для этого нового второго значения, начиная с fst, в противном случае добавьте fst к последнему списку в n_list.

1 голос
/ 06 декабря 2009

Возможно, не самый питонский ответ, но это работает:

d = {}

a = [(1,5), (5,4), (13,3), (4,3), (3,2), (14,1), (12,1)]

for value in a:
     if value[0] not in d:
         d[ value[0] ] = []
     d[ value[0] ].append( a[1] )

print d.values()
0 голосов
/ 06 декабря 2009

Не знаю, как быстро это будет для больших сетов, но вы могли бы сделать что-то подобное:

input = [
    (1,  5), (5,  4), (13, 3), (4, 3), (3, 2), (14, 1),
    (12, 1), (10, 1), (9,  1), (8, 1), (7, 1), (6,  1),
    (2,  1)
]

output = [[] for _ in xrange(input[0][1])]
for value, key in input:
    output[-key].append(value)

print output # => [[1], [5], [13, 4], [3], [14, 12, 10, 9, 8, 7, 6, 2]]
...