Я очень часто сталкиваюсь с необходимостью разбить последовательность на две подпоследовательности элементов, которые удовлетворяют и не удовлетворяют заданному предикату (сохраняя исходное относительное упорядочение).Как разбить последовательность в соответствии с предикатом?
Эта гипотетическая функция «разветвитель» будет выглядеть следующим образом в действии:
>>> data = map(str, range(14))
>>> pred = lambda i: int(i) % 3 == 2
>>> splitter(data, pred)
[('2', '5', '8', '11'), ('0', '1', '3', '4', '6', '7', '9', '10', '12', '13')]
Мой вопрос:
делает Python уже есть стандарт/встроенный способ сделать это?
Эта функциональность, конечно же, не является сложной задачей (см. Добавление ниже), но по ряду причин я предпочел бы использовать стандартный/встроенный метод, чем самокатанный.
Спасибо!
Добавление:
Лучшая функция стандарт я нашел до сих пор для обработки этой задачи в Python является itertools.groupby
. Для того, чтобы использовать его для этой конкретной задачи однако, необходимо вызвать функцию предиката дважды для каждого элемента списка, который я нахожу раздражающе глупо:
>>> import itertools as it
>>> [tuple(v[1]) for v in it.groupby(sorted(data, key=pred), key=pred)]
[('0', '1', '3', '4', '6', '7', '9', '10', '12', '13'), ('2', '5', '8', '11')]
(последний выход выше отличается от требуемого, как показано ранее в том, что подпоследовательность элементов, которые удовлетворяют предикату, наступает скорее, чем первая, но это очень незначительно и очень легко исправить при необходимости.)
Можно избежать избыточных вызовов предиката (в основном, inline memoization "), но мой лучший удар в этом становится довольно сложным, далеким от простоты splitter(data, pred)
:
>>> first = lambda t: t[0]
>>> [zip(*i[1])[1] for i in it.groupby(sorted(((pred(x), x) for x in data),
... key=first), key=first)]
[('0', '1', '3', '4', '6', '7', '9', '10', '12', '13'), ('2', '5', '8', '11')]
Кстати, если вы не заботитесь о сохранении оригинального заказа, порядок сортировки по умолчанию sorted
«S получает работу (поэтому параметр key
может быть опущен из sorted
вызова):
>>> [zip(*i[1])[1] for i in it.groupby(sorted(((pred(x), x) for x in data)),
... key=first)]
[('0', '1', '3', '4', '6', '7', '9', '10', '12', '13'), ('2', '5', '8', '11')]
Можете ли вы помочь нам понять, почему вы не хотите, чтобы написать функцию? –
Возможный дубликат [Python: разбиение списка на основе условия?] (Http://stackoverflow.com/questions/949098/python-split-a-list-based-on-a-condition) – user