Modul itertools
v jazyce Python, jak je uvedeno v oficiální dokumentaci, nabízí sadu efektivních a rychlých nástrojů pro práci s iterátory. Tyto nástroje, které lze používat jednotlivě i v kombinaci, umožňují vytvářet a manipulovat s iterátory s vysokou efektivitou z hlediska paměti i rychlosti.
Modul itertools
obsahuje funkce, které značně usnadňují práci s iterátory, zejména při zpracování rozsáhlých datových souborů. Funkce tohoto modulu umožňují pracovat s existujícími iterátory a vytvářet z nich ještě komplexnější struktury.
Dále, itertools
může vývojářům pomoci omezit chyby při práci s iterátory a psát tak kód, který je nejen čistší a čitelnější, ale také snadněji udržovatelný.
V závislosti na funkcionalitě, kterou nabízejí iterátory v rámci modulu itertools
, je lze rozdělit do následujících kategorií:
Nekonečné iterátory
Tyto iterátory jsou navrženy pro práci s nekonečnými sekvencemi. Umožňují spouštět cykly, které by teoreticky mohly běžet do nekonečna, pokud není definována podmínka pro jejich ukončení. Jsou užitečné například při simulacích nekonečných smyček nebo při generování neomezených sekvencí. V modulu itertools
najdeme tři nekonečné iterátory: count()
, cycle()
a repeat()
.
Kombinatorické iterátory
Kombinatorické iterátory poskytují funkce pro provádění operací na kartézských součinech a pro generování kombinací a permutací prvků v iterovatelných objektech. Tyto funkce jsou klíčové, pokud potřebujete nalézt všechny možné způsoby, jak uspořádat nebo kombinovat prvky v dané sekvenci. V rámci itertools
jsou k dispozici čtyři kombinatorické iterátory: product()
, permutations()
, combinations()
a combinations_with_replacement()
.
Iterátory končící na nejkratší vstupní sekvenci
Tato kategorie zahrnuje iterátory, které se používají s konečnými sekvencemi a generují výstup v závislosti na použité funkci. Příklady těchto iterátorů zahrnují: accumulate()
, chain()
, chain.from_iterable()
, compress()
, dropwhile()
, filterfalse()
, groupby()
, islice()
, pairwise()
, starmap()
, takewhile()
, tee()
a zip_longest()
.
Nyní se podíváme na to, jak fungují jednotlivé funkce z modulu itertools
, rozdělené podle jejich typů:
Nekonečné iterátory
Mezi tři nekonečné iterátory patří:
count()
Funkce count(start, step)
generuje nekonečnou posloupnost čísel, která začíná počáteční hodnotou. Funkce přijímá dva volitelné argumenty: start
a step
. Argument start
určuje, kde má posloupnost začínat. Pokud není zadán, výchozí hodnota je 0. Argument step
definuje rozdíl mezi jednotlivými po sobě jdoucími čísly. Výchozí hodnota kroku je 1.
import itertools
# count starting at 4, making steps of 2
for i in itertools.count(4, 2):
# condition to end the loop avoiding infinite looping
if i == 14:
break
else:
print(i) # output - 4, 6, 8, 10, 12
Výstup:
4
6
8
10
12
cycle()
Funkce cycle(iterable)
bere jako argument iterovatelný objekt a cyklicky prochází jeho prvky. Umožňuje tak opakovaný přístup k prvkům v pořadí, v jakém se v iterovatelném objektu nacházejí.
Například, pokud jako vstup do cycle()
předáme seznam ["red", "green", "yellow"]
, v prvním cyklu budeme mít přístup k „red“, ve druhém cyklu k „green“, poté k „yellow“. Ve čtvrtém cyklu, protože jsme již vyčerpali všechny prvky, začneme znovu od „red“ a takto budeme pokračovat do nekonečna.
Při použití cycle()
se doporučuje uložit výsledek do proměnné. Tím se vytvoří iterátor, který si uchovává svůj stav, a cyklus tak nezačíná pokaždé znovu od začátku.
import itertools
colors = ["red", "green", "yellow"]
# pass in colors into cycle()
color_cycle = itertools.cycle(colors)
print(color_cycle)
# range used to stop the infinite loop once we've printed 7 times
# next() used to return the next item from the iterator
for i in range(7):
print(next(color_cycle))
Výstup:
red
green
yellow
red
green
yellow
red
repeat()
Funkce repeat(elem, n)
přijímá dva argumenty: prvek elem
, který chceme opakovat, a počet opakování n
. Prvek, který má být opakován, může být jedna hodnota nebo iterovatelný objekt. Pokud není zadán argument n
, prvek se bude opakovat do nekonečna.
import itertools
for i in itertools.repeat(10, 3):
print(i)
Výstup:
10
10
10
Kombinatorické iterátory
Mezi kombinatorické iterátory patří:
product()
Funkce product()
se používá k výpočtu kartézského součinu iterovatelných objektů, které jí předáme. Pokud máme například dva iterovatelné objekty x = {7, 8}
a y = {1, 2, 3}
, kartézský součin x
a y
bude obsahovat všechny možné kombinace prvků z x
a y
, kde první prvek je z x
a druhý z y
. V tomto případě je kartézský součin x
a y
roven [(7, 1), (7, 2), (7, 3), (8, 1), (8, 2), (8, 3)]
.
Funkce product()
má volitelný parametr repeat
, který se používá pro výpočet kartézského součinu iterovatelného objektu sama se sebou. Parametr repeat
definuje počet opakování pro každý prvek ze vstupních iterovatelných objektů při výpočtu kartézského součinu.
Například, volání product('ABCD', repeat=2)
nám dá kombinace jako ('A', 'A')
, ('A', 'B')
, ('A', 'C')
, atd. Pokud by repeat
byl nastaven na 3, funkce by vrátila kombinace jako ('A', 'A', 'A')
, ('A', 'A', 'B')
, ('A', 'A', 'C')
, ('A', 'A', 'D')
atd.
from itertools import product
# product() with the optional repeat argument
print("product() with the optional repeat argument ")
print(list(product('ABC', repeat = 2)))
# product with no repeat
print("product() WITHOUT an optional repeat argument")
print(list(product([7,8], [1,2,3])))
Výstup:
product() with the optional repeat argument
[('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'B'), ('B', 'C'), ('C', 'A'), ('C', 'B'), ('C', 'C')]
product() WITHOUT an optional repeat argument
[(7, 1), (7, 2), (7, 3), (8, 1), (8, 2), (8, 3)]
permutations()
Funkce permutations(iterable, group_size)
vrací všechny možné permutace prvků v iterovatelném objektu, který jí byl předán. Permutace představuje počet způsobů, jak lze prvky v dané množině uspořádat. Funkce permutations()
má volitelný argument group_size
. Pokud není group_size
zadán, vygenerované permutace budou mít stejnou délku jako délka iterovatelného objektu.
import itertools
numbers = [1, 2, 3]
sized_permutations = list(itertools.permutations(numbers,2))
unsized_permuatations = list(itertools.permutations(numbers))
print("Permutations with a size of 2")
print(sized_permutations)
print("Permutations with NO size argument")
print(unsized_permuatations)
Výstup:
Permutations with a group size of 2
[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
Permutations with NO size argument
[(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]
combinations()
Funkce combinations(iterable, size)
vrací všechny možné kombinace dané délky z prvků v iterovatelném objektu, který jí byl předán. Argument size
určuje velikost každé kombinace.
Výsledky jsou seřazeny. Kombinace se mírně liší od permutací. V permutaci záleží na pořadí prvků, ale v kombinaci na pořadí prvků nezáleží. Například v sadě [A, B, C]
existuje 6 permutací: AB, AC, BA, BC, CA, CB, ale pouze 3 kombinace: AB, AC, BC.
import itertools
numbers = [1, 2, 3,4]
size2_combination = list(itertools.combinations(numbers,2))
size3_combination = list(itertools.combinations(numbers, 3))
print("Combinations with a size of 2")
print(size2_combination)
print("Combinations with a size of 3")
print(size3_combination)
Výstup:
Combinations with a size of 2
[(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
Combinations with a size of 3
[(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]
combinations_with_replacement()
Funkce combinations_with_replacement(iterable, size)
generuje všechny možné kombinace dané délky z prvků v iterovatelném objektu, který jí byl předán, a zároveň umožňuje opakování prvků ve výsledných kombinacích. Argument size
určuje velikost generovaných kombinací.
Tato funkce se liší od funkce combinations()
v tom, že poskytuje kombinace, ve kterých se prvek může objevit více než jednou. Například je možné získat kombinaci jako (1, 1)
, což s pomocí combinations()
není možné.
import itertools
numbers = [1, 2, 3,4]
size2_combination = list(itertools.combinations_with_replacement(numbers,2))
print("Combinations_with_replacement => size 2")
print(size2_combination)
Výstup:
Combinations_with_replacement => size 2
[(1, 1), (1, 2), (1, 3), (1, 4), (2, 2), (2, 3), (2, 4), (3, 3), (3, 4), (4, 4)]
Ukončení iterátorů
Tato kategorie zahrnuje iterátory jako:
accumulate()
Funkce accumulate(iterable, function)
přijímá iterovatelný objekt a druhý volitelný argument, který je funkce. Poté vrací akumulovaný výsledek aplikace dané funkce v každé iteraci na prvky v iterovatelném objektu. Pokud není zadána žádná funkce, provádí se sčítání a vrací se akumulované výsledky.
import itertools
import operator
numbers = [1, 2, 3, 4, 5]
# Accumulate the sum of numbers
accumulated_val = itertools.accumulate(numbers)
accumulated_mul = itertools.accumulate(numbers, operator.mul)
print("Accumulate with no function")
print(list(accumulated_val))
print("Accumulate with multiplication")
print(list(accumulated_mul))
Výstup:
Accumulate with no function
[1, 3, 6, 10, 15]
Accumulate with multiplication
[1, 2, 6, 24, 120]
chain()
Funkce chain(iterable_1, iterable_2, ...)
přijímá několik iterovatelných objektů a zřetězí je dohromady. Tím vytvoří jediný iterovatelný objekt, který obsahuje hodnoty ze všech iterovatelných objektů, které byly předány funkci chain()
.
import itertools
letters = ['A', 'B', 'C', 'D']
numbers = [1, 2, 3]
colors = ['red', 'green', 'yellow']
# Chain letters and numbers together
chained_iterable = list(itertools.chain(letters, numbers, colors))
print(chained_iterable)
Výstup:
['A', 'B', 'C', 'D', 1, 2, 3, 'red', 'green', 'yellow']
chain.from_iterable()
Funkce chain.from_iterable(iterable)
se chová podobně jako funkce chain()
, ale s tím rozdílem, že přijímá pouze jeden iterovatelný objekt, který obsahuje dílčí iterovatelné objekty. Ty pak spojí dohromady.
import itertools
letters = ['A', 'B', 'C', 'D']
numbers = [1, 2, 3]
colors = ['red', 'green', 'yellow']
iterable = ['hello',colors, letters, numbers]
chain = list(itertools.chain.from_iterable(iterable))
print(chain)
Výstup:
['h', 'e', 'l', 'l', 'o', 'red', 'green', 'yellow', 'A', 'B', 'C', 'D', 1, 2, 3]
compress()
Funkce compress(data, selectors)
přijímá dva argumenty: data
, což je iterovatelný objekt, a selectors
, což je iterovatelný objekt obsahující booleovské hodnoty True
a False
. Jako alternativu lze použít také 1
a 0
. Funkce compress()
filtruje data podle odpovídajících prvků v selektorech.
Hodnoty v data
, které odpovídají True
nebo 1
v selectors
, jsou vybrány, zatímco ostatní, které odpovídají False
nebo 0
, jsou ignorovány. Pokud v selectors
předáme méně booleovských hodnot, než je počet položek v data
, všechny prvky za předanými logickými hodnotami v selektorech se ignorují.
import itertools
# data has 10 items
data = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']
# passing in 9 selector items
selectors = [True, False, 1, False, 0, 1, True, False, 1]
# Select elements from data based on selectors
filtered_data = list(itertools.compress(data, selectors))
print(filtered_data)
Výstup:
['A', 'C', 'F', 'G', 'I']
dropwhile()
Funkce dropwhile(function, sequence)
přijímá funkci s podmínkou, která vrací True
nebo False
, a sekvenci hodnot. Funkce dropwhile()
vynechává hodnoty ze sekvence, dokud splnění podmínky nevrátí False
. Jakmile podmínka vrátí False
, zbylé prvky se zahrnou do výsledků, bez ohledu na to, zda splňují podmínku.
import itertools
numbers = [1, 2, 3, 4, 5, 1, 6, 7, 2, 1, 8, 9, 0, 7]
# Drop elements until the passed condition is False
filtered_numbers = list(itertools.dropwhile(lambda x: x < 5, numbers))
print(filtered_numbers)
Výstup:
[5, 1, 6, 7, 2, 1, 8, 9, 0, 7]
filterfalse()
Funkce filterfalse(function, sequence)
přijímá funkci s podmínkou, která se vyhodnotí jako True
nebo False
, a sekvenci. Funkce poté vrací hodnoty ze sekvence, pro které se podmínka ve funkci vyhodnotí jako False
.
import itertools
numbers = [1, 2, 3, 4, 2, 3, 5, 6, 5, 8, 1, 2, 3, 6, 2, 7, 4, 3]
# Filter elements for which condition is False
filtered_numbers = list(itertools.filterfalse(lambda x: x < 4, numbers))
print(filtered_numbers)
Výstup:
[4, 5, 6, 5, 8, 6, 7, 4]
groupby()
Funkce groupby(iterable, key)
přijímá iterovatelný objekt a klíč a poté vytvoří iterátor, který vrací po sobě jdoucí klíče a skupiny. Aby toto fungovalo, iterovatelný objekt, který je jí předán, musí být seřazen podle stejné klíčové funkce. Klíčová funkce vypočítává klíčovou hodnotu pro každý prvek v iterovatelném objektu.
import itertools
input_list = [("Domestic", "Cow"), ("Domestic", "Dog"), ("Domestic", "Cat"),("Wild", "Lion"), ("Wild", "Zebra"), ("Wild", "Elephant")]
classification = itertools.groupby(input_list,lambda x: x[0])
for key,value in classification:
print(key,":",list(value))
Výstup:
Domestic : [('Domestic', 'Cow'), ('Domestic', 'Dog'), ('Domestic', 'Cat')]
Wild : [('Wild', 'Lion'), ('Wild', 'Zebra'), ('Wild', 'Elephant')]
islice()
Funkce islice(iterable, start, stop, step)
umožňuje rozdělit iterovatelný objekt na segmenty s pomocí zadaných hodnot start
, stop
a step
. Argument step
je volitelný. Počítání začíná od 0 a prvek s indexem stop
není zahrnut.
import itertools
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
# Select elements within a range
selected_numbers = list(itertools.islice(numbers, 2, 10))
selected_numbers_step= list(itertools.islice(numbers, 2, 10,2))
print("islice without setting a step value")
print(selected_numbers)
print("islice with a step value of 2")
print(selected_numbers_step)
Výstup:
islice without setting a step value
[3, 4, 5, 6, 7, 8, 9, 10]
islice with a step value of 2
[3, 5, 7, 9]
pairwise()
Funkce pairwise(iterable)
vrací po sobě jdoucí překrývající se páry z prvků v iterovatelném objektu v pořadí, v jakém se objevují v iterovatelném objektu. Pokud má iterovatelný objekt méně než dvě hodnoty, bude výsledek funkce pairwise()
prázdný.
from itertools import pairwise
numbers = [1, 2, 3, 4, 5, 6, 7, 8]
word = 'WORLD'
single = ['A']
print(list(pairwise(numbers)))
print(list(pairwise(word)))
print(list(pairwise(single)))
Výstup:
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8)]
[('W', 'O'), ('O', 'R'), ('R', 'L'), ('L', 'D')]
[]
starmap()
Funkce starmap(function, iterable)
je funkce, která se používá místo map()
, pokud jsou parametry argumentů již seskupeny do n-tic. Funkce starmap()
aplikuje danou funkci na prvky iterovatelného objektu. Iterovatelný objekt by měl mít prvky seskupené do n-tic.
import itertools
iter_starmap = [(123, 63, 13), (5, 6, 52), (824, 51, 9), (26, 24, 16), (14, 15, 11)]
print (list(itertools.starmap(min, iter_starmap)))
Výstup:
[13, 5, 9, 16, 11]
takewhile()
Funkce takewhile(function, iterable)
funguje opačně než dropwhile()
. Funkce takewhile()
přijímá funkci s podmínkou, která má být vyhodnocena, a iterovatelný objekt. Zahrnuje všechny prvky v iterovatelném objektu, které splňují podmínku ve funkci, dokud není vrácena hodnota False
. Jakmile je vrácena hodnota False
, všechny následující prvky v iterovatelném objektu jsou ignorovány.
import itertools
numbers = [1, 2, 3, 4, 5, 1, 6, 7, 2, 1, 8, 9, 0, 7]
# Drop elements until the passed condition is False
filtered_numbers = list(itertools.takewhile(lambda x: x < 5, numbers))
print(filtered_numbers)
Výstup:
[1, 2, 3, 4]
tee()
Funkce tee(iterable, n)
přijímá iterovatelný objekt a vrací několik nezávislých iterátorů. Počet iterátorů, které mají být vráceny, se nastavuje pomocí n
, což je ve výchozím nastavení 2.
import itertools
numbers = [1, 2, 3, 4, 5]
# Create two independent iterators from numbers
iter1, iter2 = itertools.tee(numbers, 2)
print(list(iter1))
print(list(iter2))
Výstup:
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
zip_longest()
Funkce zip_longest(iterables, fillvalue)
přijímá několik iterovatelných objektů a volitelnou hodnotu fillvalue
. Funkce vrací iterátor, který agreguje prvky z každého z iterátorů, které byly předány. Pokud iterátory nemají stejnou délku, chybějící hodnoty jsou nahrazeny hodnotou fillvalue
, dokud není vyčerpán nejdelší iterovatelný objekt.
import itertools
names = ['John', 'mathew', 'mary', 'Alice', 'Bob', 'Charlie', 'Fury']
ages = [25, 30, 12, 13, 42]
# Combine name and ages, filling in missing ages with a dash
combined = itertools.zip_longest(names, ages, fillvalue="-")
for name, age in combined:
print(name, age)
Výstup:
John 25
mathew 30
mary 12
Alice 13
Bob 42
Charlie -
Fury -
Závěr
Modul itertools
v Pythonu je důležitý soubor nástrojů pro vývojáře v Pythonu. Funkce tohoto modulu se hojně využívají ve funkcionálním programování, při zpracování a transformaci dat, filtrování a výběru dat, seskupování a agregaci, kombinování iterovatelných objektů, v kombinatorice a při práci s nekonečnými sekvencemi.
Jako vývojář v Pythonu budete mít velký prospěch ze znalosti a použití modulu itertools
, proto nezapomeňte využít tento článek pro seznámení s možnostmi, které nabízí.