До речі, приклад з 1-го повідомлення, якщо розписати його до робочого багаторядкового варіанту:
for i in range(10):
print(i)
if (i == 5): break
й звести далі до більш загального вигляду (де ми вже не можемо скористатися тим, що послідовність повністю передбачувана):
for i in якась_послідовність:
print(i)
if якась_умова: break
зводиться до функціонального виразу з певними труднощами — через те, що вихід відбувається після дії в циклі, а не перед нею. Якби було так:
for i in range(10):
if (i == 5):break
print(i)
це можна було б переписати так:
import itertools as it
for i in it.takewhile(lambda i: not(i == 5), range(10)): print(i)
Проте, оскільки нам треба було включити в вивід і той елемент, на якому умова виходу спрацювала, треба зробити це якось інакше. Було б добре, якби існувала функція takeuntil, яка повертала б результат takewhile й наступний елемент. Напишімо її.
Наприклад, можна порахувати довжину результату takewhile, додати 1, вибрати потрібну кількість елементів за допомогою islice:
import itertools as it
def takeuntil(cond, seq):
seq, seq0=it.tee(seq) # клонуємо послідовність для безконфліктної роботи з ітераторами
l=len(tuple(it.takewhile(lambda x:not cond(x), seq0))) + 1
return it.islice(seq, l)
Після чого використати цю функцію подібно до takewhile:
for i in it.takeuntil(lambda i: (i == 5), range(10)): print(i)
Маючи час та натхнення, можна переписати всю функцію takeuntil як функціональний вираз і використати цей вираз замість її імені при виклику, але такий код буде важче читати.