Сон разума: снится Python
Вот что родил мой мозг в текущем проекте:
def trim(letter):
SKIPLEAD = object()
SKIPINNE = object()
todelete, stage, skipped = [], SKIPLEAD, 0
for idx, blank in enumerate([x == '' for x in letter]):
if stage == SKIPLEAD:
if blank:
todelete.append(idx)
else:
stage = SKIPINNE
else:
if blank:
skipped += 1
todelete.append(idx)
else:
if 0 < skipped < 3:
todelete = todelete[0:-skipped]
return [letter[idx] for idx in set(range(0, len(letter))) - set(todelete)]
Комментарии 20
from itertools import dropwhile, groupby, chain
def trim(letter):
letter = dropwhile(lambda l: not l, letter)
empty = []
for l in letter:
if not l:
empty.append(l)
else:
if 0 < len(empty) < 3:
for e in empty:
yield e
empty = []
yield l
А потом я позвал elephantum'а, который помнит функцию groupby, которую я не помню. Вышел отрыв башки
def trim(ll):
for k, grp in groupby(
dropwhile(
lambda l: not l,
chain(ll, ['', '', ''])),
lambda x:x):
grp = list(grp)
if k or len(grp) < 3:
for i in grp: yield i
Так что выкидывай свои императивные привычки
P.S. elephantum: «а на Хаскеле это было бы еще проще»
P.S. hCard так и не пашет. Вот они сторонние сервисы! Буду глубоко отлаживать.
Зря я не уделял внимание itertools, очень и очень полезная штука.
from itertools import chain, groupby, imap
def trim(letters):
return chain(*imap(lambda (k, g): g if k or len(g) < 3 else [], imap(lambda (k, g): (k, list(g)), groupby(chain([''] * 3, letters, [''] * 3), lambda x:x))))
Да, это в одну строку
def trim(letters):
letters = chain([''] * 3, letters, [''] * 3)
letters = groupby(letters, lambda x:x)
letters = imap(lambda (k, g): (k, list(g)), letters)
letters = imap(lambda (k, g): g if k or len(g) < 3 else [], letters)
return chain(*letters)
кстати, надо chain вынести за dropwhile в варианте №2. ['']*3 я тоже догадался использовать :)
Щас ещё свой вариант выложу ;)
Оказывается, на генераторных выражениях покороче получается
from itertools import chain, groupby
def trim(letters):
return chain(*(g for k, g in ((k, list(g)) for k, g in groupby(chain([''] * 3, letters, [''] * 3), lambda x:x)) if k or len(g) < 3))
Кстати, расшифровка лишняя, голову я уже проапгрейдил. Вот мой вариант (вызов *func подсмотрел у тебя, до этого сам не додумался, хотя синтаксис знаю, с ним отвалился и ifilterfalse, которым я отфильтровывал пустой список):
print [x for x in chain(*starmap(lambda item, grp: grp if item != '' or len(grp)
Ага, я генератором условие пытался сделать, но упёрся в необходимость преобразовования grp в list, показалось неэстетичным. Так лучше, да.
В общем, я
В итоге, вот что вышло (задачу я модифицировал, так как аргумент замену 3+ пустых строк на одну — разумен):
print [x for x in chain(*starmap(lambda item, grp: [grp, ['']][item == '' and len(grp)>2], iter((i, list(g)) for i, g in groupby(chain(['']*3, letter, ['']*3), lambda
Это то, что мне не хватало при переходе с Perl на PHP. Спасибо за itertool :)
не забыть завтра при замене этого куска выкинуть «print [x for x in» и вставить туда просто list.
Чёрт. Не тот вариант оставил. Щас напишу отдельным постом.
Собственно, основная прелесть itertools именно в этом: они позволяют работать с итераторами любой природы, даже бесконечными.
Ага, я поковырял что вышло и понял где у моя ошибка. Я просто не поставил скобки вокруг генератора и решил, что генераторы и итераторы — вещи разные.
Вынес результат отдельным постом, видоизменив задачу. Кстати, если ещё не спишь, подскажи: a if b else c есть в __future__, если есть, то как подключается, если сходу вспомнишь. Если нет, завтра сам прочитаю.