разделить список кортежей в списках списка кортежей

У меня есть список кортежей, например:

[(1,a),(2,b), (1, e), (3, b), (2,c), (4,d), (1, b), (0,b), (6, a), (8, e)]

Я хочу разбить его на список списков на каждом "b"

[[(1,a),(2,b)], [(1, e), (3, b)], [(2,c), (4,d), (1, b)], [(0,b)], [(6, a), (8, e)]]

есть ли питонический способ сделать это?


person Abhishek Thakur    schedule 20.03.2014    source источник
comment
Я бы сказал, что прямой цикл for здесь является питоническим, поскольку намерение может быть неясным, если вы исказите это в какой-то генератор понимания. Явное лучше, чем неявное.   -  person dornhege    schedule 20.03.2014
comment
Всегда ли буквы b встречаются одинаково, как здесь?   -  person Jayanth Koushik    schedule 20.03.2014
comment
нет. они не делают. я обновил пример   -  person Abhishek Thakur    schedule 20.03.2014


Ответы (4)


Вы можете использовать yield.

def get_groups(lst):
    t = []
    for i in lst:
        t.append(i)
        if i[1] == 'b':
            yield t
            t = []
    if t:
        yield t

my_list = [(1,a),(2,b), (1, e), (3, b), (2,c), (1, b), (0,b)]
groups = list(get_groups(my_list))
person Jayanth Koushik    schedule 20.03.2014
comment
Не работает, если последний элемент не заканчивается на b. Вы должны проверить, содержит ли t элементы, и выдать их в этом случае в конце вашей функции. - person sloth; 20.03.2014
comment
Что делать, если последний не заканчивается на «b», включать его или нет? - person Raul Guiu; 20.03.2014
comment
Это должно быть включено - person Abhishek Thakur; 20.03.2014
comment
Это нехорошо. Изменение вопроса после. - person Raul Guiu; 20.03.2014
comment
@Avempace Я добавил еще один кортеж, чтобы было ясно, что даже если он не заканчивается на b, он должен возвращать полный список в виде подсписка. - person Abhishek Thakur; 20.03.2014
comment
Спасибо! Изменил ответ для этого. Я все равно экспериментировал. Я бы не стал так делать в производстве, как сказал Джаниант. - person Raul Guiu; 20.03.2014
comment
Код не работает для огромных списков без b. Поэтому я принял ответ @thefourtheye, хотя мне нравятся генераторы. - person Abhishek Thakur; 21.03.2014
comment
@AbhishekThakur: у нас обоих одинаковое решение, за исключением того, что здесь используется генератор. Почему это не сработает для «огромных списков»? - person Jayanth Koushik; 21.03.2014
comment
Извиняюсь. Это не огромные списки. Он производит повторения, и сгенерированный список становится огромным - person Abhishek Thakur; 21.03.2014

Мое решение прямо в консоли Python:

>>> l = [(1,'a'),(2,'b'), (1, 'e'), (3, 'b'), (2,'c'), (1, 'b'), (0,'b')]
>>> b = [-1] + [x for x, y in enumerate(l) if y[1] == 'b' or x == len(l)-1]
>>> u = zip(b,b[1:])
>>> m = [l[x[0]+1:x[1]+1] for x in u]
>>> m
[[(1, 'a'), (2, 'b')], [(1, 'e'), (3, 'b')], [(2, 'c'), (1, 'b')], [(0, 'b')]]

b — это индексы кортежей с буквой "b", начиная с -1.

[-1, 1, 3, 5, 6]

u — кортежи индексов подсписка, который мы создадим:

[(-1, 1), (1, 3), (3, 5), (5, 6)]

И для случая, не заканчивающегося кортежем на «b»:

[(1, 'a'), (2, 'b'), (1, 'e'), (3, 'b'), (2, 'c'), (1, 'b'), (0, 'b'), (6, 'a'), (8, 'e')]

дает:

[[(1, 'a'), (2, 'b')], [(1, 'e'), (3, 'b')], [(2, 'c'), (1, 'b')], [(0, 'b')], [(6, 'a'), (8, 'e')]]    
person Raul Guiu    schedule 20.03.2014
comment
Это менее интуитивно и менее эффективно, чем простой цикл for. - person Jayanth Koushik; 20.03.2014
comment
В вопросах говорится, есть ли какой-нибудь питонический способ сделать это? Только показаны другие альтернативы. - person Raul Guiu; 20.03.2014
comment
Интуитивность - большая часть "pythonic". - person Jayanth Koushik; 20.03.2014
comment
Это не удается, если последний элемент не содержит 'b'. - person Ashwini Chaudhary; 20.03.2014
comment
Что это должно дать? Я пробовал и разбивал на блоки, оканчивающиеся кортежем на b. Вы предполагаете, что что-то не указано в вопросе? - person Raul Guiu; 20.03.2014
comment
теперь исправлено добавлением x == len(l)-1 - person Raul Guiu; 20.03.2014

Что насчет этого?

xs = [(1, 'a'), (2, 'b'), (1, 'e'), (3, 'b'), (2, 'c'), (4, 'd'), (1, 'b'), (0, 'b'), (6, 'a'), (8, 'e')]

result = [[]]
for x in xs:
  result[0].append(x)
  if x[1] == 'b':
    result.insert(0, [])
result.reverse()
person Aegis    schedule 20.03.2014

Чистое решение итератора:

def get_groups(lst):
    i = iter(lst)
    def row(x):
        while True:
            yield x
            if x[1] == 'b':
                return
            x = next(i)

    for x in i:
        yield row(x)

for r in get_groups(data):
    print list(r)
person Eric    schedule 20.03.2014