Python · Синтаксис · Проміжний
itertools
Опануйте модуль itertools у Python: інструменти для роботи з ітераторами, генерації послідовностей та ефективного розв'язання комбінаторних задач.
Короткий вступ до теми та пояснення перед вправами (вправи нижче):
Комбінаторика з itertools
#Довідник: itertools
#Вправи:
Вирівняти вкладений список
#Напишіть функцію `flatten(nested)`, яка приймає список списків і повертає плоский список за допомогою `itertools.chain.from_iterable`. Приклад: `flatten([[1, 2], [3], [4, 5, 6]])` → `[1, 2, 3, 4, 5, 6]`.
from itertools import chain
def flatten(nested):
pass
print(flatten([[1, 2], [3], [4, 5, 6]]))
# [1, 2, 3, 4, 5, 6]
Рішення
from itertools import chain
def flatten(nested):
return list(chain.from_iterable(nested))
print(flatten([[1, 2], [3], [4, 5, 6]]))
# [1, 2, 3, 4, 5, 6]
Перші N з генератора
#Напишіть функцію `first_n(gen, n)`, яка повертає перші `n` елементів з будь-якого генератора або ітератора у вигляді списку, використовуючи `itertools.islice`. Приклад: `first_n((x**2 for x in range(100)), 5)` → `[0, 1, 4, 9, 16]`.
from itertools import islice
def first_n(gen, n):
pass
print(first_n((x**2 for x in range(100)), 5))
# [0, 1, 4, 9, 16]
Рішення
from itertools import islice
def first_n(gen, n):
return list(islice(gen, n))
print(first_n((x**2 for x in range(100)), 5))
# [0, 1, 4, 9, 16]
Планувальник round-robin
#Напишіть функцію `round_robin(tasks)`, яка приймає список назв завдань і повертає нескінченний цикловий ітератор за допомогою `itertools.cycle`. Потім використайте `itertools.islice` для отримання перших 8 призначень. Приклад: `list(islice(round_robin(["A", "B", "C"]), 8))` → `["A", "B", "C", "A", "B", "C", "A", "B"]`.
from itertools import cycle, islice
def round_robin(tasks):
pass
print(list(islice(round_robin(["A", "B", "C"]), 8)))
# ["A", "B", "C", "A", "B", "C", "A", "B"]
Рішення
from itertools import cycle, islice
def round_robin(tasks):
return cycle(tasks)
print(list(islice(round_robin(["A", "B", "C"]), 8)))
# ["A", "B", "C", "A", "B", "C", "A", "B"]
Злити нерівні послідовності
#Напишіть функцію `merge_sequences(seq1, seq2, seq3, fill=None)`, яка об'єднує три послідовності поелементно за допомогою `itertools.zip_longest`, використовуючи `fill` як відсутнє значення. Повертає результат як список кортежів. Приклад: `merge_sequences([1,2,3], ["a","b"], [True], fill=0)` → `[(1,"a",True), (2,"b",0), (3,0,0)]`.
from itertools import zip_longest
def merge_sequences(seq1, seq2, seq3, fill=None):
pass
print(merge_sequences([1, 2, 3], ["a", "b"], [True], fill=0))
# [(1, "a", True), (2, "b", 0), (3, 0, 0)]
Рішення
from itertools import zip_longest
def merge_sequences(seq1, seq2, seq3, fill=None):
return list(zip_longest(seq1, seq2, seq3, fillvalue=fill))
print(merge_sequences([1, 2, 3], ["a", "b"], [True], fill=0))
# [(1, "a", True), (2, "b", 0), (3, 0, 0)]
Накопичений максимум
#Напишіть функцію `running_max(numbers)`, яка повертає список, де кожен елемент є максимальним значенням, яке зустрічалось дотепер у `numbers`. Використовуйте `itertools.accumulate`. Приклад: `running_max([3, 1, 4, 1, 5, 9, 2, 6])` → `[3, 3, 4, 4, 5, 9, 9, 9]`.
from itertools import accumulate
import operator
def running_max(numbers):
pass
print(running_max([3, 1, 4, 1, 5, 9, 2, 6]))
# [3, 3, 4, 4, 5, 9, 9, 9]
Рішення
from itertools import accumulate
import operator
def running_max(numbers):
return list(accumulate(numbers, func=max))
print(running_max([3, 1, 4, 1, 5, 9, 2, 6]))
# [3, 3, 4, 4, 5, 9, 9, 9]
Декартовий добуток: сітка
#Напишіть функцію `grid(rows, cols)`, яка повертає всі пари координат (row, col) для сітки заданих розмірів, використовуючи `itertools.product`. Приклад: `grid(2, 3)` → `[(0,0), (0,1), (0,2), (1,0), (1,1), (1,2)]`.
from itertools import product
def grid(rows, cols):
pass
print(grid(2, 3))
# [(0,0), (0,1), (0,2), (1,0), (1,1), (1,2)]
Рішення
from itertools import product
def grid(rows, cols):
return list(product(range(rows), range(cols)))
print(grid(2, 3))
# [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]
Всі пари (комбінації)
#Напишіть функцію `all_pairs(items)`, яка повертає всі унікальні невпорядковані пари елементів (елемент не поєднується з собою). Використовуйте `itertools.combinations`. Приклад: `all_pairs(["A", "B", "C", "D"])` → `[("A","B"), ("A","C"), ("A","D"), ("B","C"), ("B","D"), ("C","D")]`.
from itertools import combinations
def all_pairs(items):
pass
print(all_pairs(["A", "B", "C", "D"]))
# [("A","B"), ("A","C"), ("A","D"), ("B","C"), ("B","D"), ("C","D")]
Рішення
from itertools import combinations
def all_pairs(items):
return list(combinations(items, 2))
print(all_pairs(["A", "B", "C", "D"]))
# [("A", "B"), ("A", "C"), ("A", "D"), ("B", "C"), ("B", "D"), ("C", "D")]
Групування за категорією
#Напишіть функцію `group_by(items, key_func)`, яка групує список елементів за функцією ключа і повертає словник, що відображає кожен ключ на список елементів. Використовуйте `itertools.groupby` (пам'ятайте спочатку відсортувати). Приклад: з `items = ["apple", "ant", "banana", "bear", "cherry"]` і `key_func = lambda w: w[0]`, результат: `{"a": ["ant", "apple"], "b": ["banana", "bear"], "c": ["cherry"]}`.
from itertools import groupby
def group_by(items, key_func):
pass
words = ["apple", "ant", "banana", "bear", "cherry"]
print(group_by(words, lambda w: w[0]))
# {"a": ["ant", "apple"], "b": ["banana", "bear"], "c": ["cherry"]}
Рішення
from itertools import groupby
def group_by(items, key_func):
sorted_items = sorted(items, key=key_func)
result = {}
for key, group in groupby(sorted_items, key=key_func):
result[key] = list(group)
return result
words = ["apple", "ant", "banana", "bear", "cherry"]
print(group_by(words, lambda w: w[0]))
# {"a": ["ant", "apple"], "b": ["banana", "bear"], "c": ["cherry"]}
takewhile: читати до розділювача
#Напишіть функцію `read_until_empty(lines)`, яка приймає список рядків і повертає тільки рядки до першого порожнього рядка (або рядка що містить тільки пробіли), використовуючи `itertools.takewhile`. Приклад: `read_until_empty(["hello", "world", "", "more", "text"])` → `["hello", "world"]`.
from itertools import takewhile
def read_until_empty(lines):
pass
print(read_until_empty(["hello", "world", "", "more", "text"]))
# ["hello", "world"]
Рішення
from itertools import takewhile
def read_until_empty(lines):
return list(takewhile(lambda line: line.strip() != "", lines))
print(read_until_empty(["hello", "world", "", "more", "text"]))
# ["hello", "world"]
Генератор паролів
#Напишіть функцію `generate_passwords(chars, length, count)`, яка генерує `count` унікальних паролів довжиною `length` символів, де кожен пароль будується з `itertools.product(chars, repeat=length)`. Повертає перші `count` добутків як об'єднані рядки. Приклад: `generate_passwords("ab", 2, 4)` → `["aa", "ab", "ba", "bb"]` (використовуйте product у порядку, без випадковості).
from itertools import product, islice
def generate_passwords(chars, length, count):
pass
print(generate_passwords("ab", 2, 4))
# ["aa", "ab", "ba", "bb"]
Рішення
from itertools import product, islice
def generate_passwords(chars, length, count):
return ["".join(p) for p in islice(product(chars, repeat=length), count)]
print(generate_passwords("ab", 2, 4))
# ["aa", "ab", "ba", "bb"]