как разделить список на две части в точке, где предикат является первым False

Я все думаю, что для этого должна быть функция, но я поискал подходящие места (google, itertools docs, методы списков, другие вопросы SO), но нигде не нашел достаточно чего Я искал.

Наивная и рабочая реализация:

def split_at_first_false(pred, seq):
    first = []
    second = []
    true_so_far = True
    for item in seq:
        if true_so_far and pred(item):
            first.append(item)
        else:
            true_so_far = False
            second.append(item)
    return first, second

print split_at_first_false(str.isalpha, "abc1a2b")
# (['a', 'b', 'c'], ['1', 'a', '2', 'b'])

Это работает, но кажется неправильным. Должен быть лучший способ сделать это!

РЕДАКТИРОВАТЬ: Я закончил с использованием немного измененной версии последнего предложения senderle после просмотра ответов:

from itertools import chain

def split_at_pred(pred, seq):
    head = []
    it = iter(seq)
    for i in it:
        if not pred(i):
            head.append(i)
        else:
            return iter(head), chain([i], it)
    return iter(head), iter([])

Это коротко и элегантно, вывод - два итератора, независимо от того, не имеет значения ввод (строки, списки, итераторы), и в качестве бонуса он даже работает со следующим вводом:

from itertools import count
split_at_pred(lambda x: x == 5, count())

У других решений, которые вообще работают с итераторами, с этим вводом не хватит памяти. (Обратите внимание, что это - это просто бонус. Я даже не думал о бесконечных итераторах, когда писал этот вопрос)

9
задан Lauritz V. Thaulow 14 July 2011 в 09:05
поделиться