Разделить список кортежей на подсписки того же поля кортежей - PullRequest
19 голосов
/ 11 ноября 2011

У меня огромный список кортежей в этом формате. Второе поле каждого кортежа - это поле категории.

    [(1, 'A', 'foo'),
    (2, 'A', 'bar'),
    (100, 'A', 'foo-bar'),

    ('xx', 'B', 'foobar'),
    ('yy', 'B', 'foo'),

    (1000, 'C', 'py'),
    (200, 'C', 'foo'),
    ..]

Каков наиболее эффективный способ разбить его на подсписки той же категории (A, B, C и т. Д.)?

Ответы [ 3 ]

23 голосов
/ 11 ноября 2011

Используйте itertools.groupby :

import itertools
import operator

data=[(1, 'A', 'foo'),
    (2, 'A', 'bar'),
    (100, 'A', 'foo-bar'),

    ('xx', 'B', 'foobar'),
    ('yy', 'B', 'foo'),

    (1000, 'C', 'py'),
    (200, 'C', 'foo'),
    ]

for key,group in itertools.groupby(data,operator.itemgetter(1)):
    print(list(group))

выходов

[(1, 'A', 'foo'), (2, 'A', 'bar'), (100, 'A', 'foo-bar')]
[('xx', 'B', 'foobar'), ('yy', 'B', 'foo')]
[(1000, 'C', 'py'), (200, 'C', 'foo')]

Или, чтобы создать один список с каждой группой в качестве подсписка, вы можете использоватьпонимание списка:

[list(group) for key,group in itertools.groupby(data,operator.itemgetter(1))]

Второй аргумент itertools.groupby - это функция, которая itertools.groupby применяется к каждому элементу в data (первый аргумент).Ожидается, что он вернет key.itertools.groupby затем группирует все смежные элементы с одинаковыми key.

operator.itemgetter (1) отбирает второй элемент в последовательности.

ДляНапример, если

row=(1, 'A', 'foo')

, то

operator.itemgetter(1)(row)

равно 'A'.


Как указывает @eryksun в комментариях, если категориикортежи появляются в некотором случайном порядке, затем вы должны сначала отсортировать data перед применением itertools.groupby.Это связано с тем, что itertools.groupy собирает только смежных элементов с одинаковым ключом в группы.

Для сортировки кортежей по категориям используйте:

data2=sorted(data,key=operator.itemgetter(1))
1 голос
/ 24 января 2019

collections.defaultdict

itertools.groupby требует, чтобы входные данные были отсортированы по ключевому полю, в противном случае вам придется отсортировать сначала , в результате чего O (*)1009 * n log n ) стоимость.Для гарантированной сложности времени O ( n ) вы можете использовать defaultdict списков:

from collections import defaultdict

dd = defaultdict(list)
for item in data:
    dd[item[1]].append(item)

res = list(dd.values())

print(res)

[[(1, 'A', 'foo'), (2, 'A', 'bar'), (100, 'A', 'foo-bar')],
 [('xx', 'B', 'foobar'), ('yy', 'B', 'foo')],
 [(1000, 'C', 'py'), (200, 'C', 'foo')]]
0 голосов
/ 08 сентября 2012

Чтобы получить несколько списков синглетонов из списка кортежей:

foo = ((1,2), (3, 4), (5, 6), (7,8) , (9, 10))
[[z[i] for z in foo] for i in (0,1)]

Если вы предпочитаете получать несколько кортежей синглетонов:

zip(*[(1,4),(2,5),(3,6)])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...