Selon la documentation de Python, le module itertools
offre un ensemble d’outils efficaces en termes de rapidité et d’utilisation de la mémoire pour manipuler les itérateurs en Python. Ces instruments, utilisables individuellement ou en combinaison, permettent de créer et d’interagir avec des itérateurs de manière concise et performante.
Ce module propose des fonctions facilitant l’opération sur les itérateurs, notamment lors du traitement de grands volumes de données. Les fonctions d’itertools
peuvent être appliquées aux itérateurs existants pour générer des itérateurs Python encore plus sophistiqués.
De plus, itertools
contribue à réduire les erreurs lors de la manipulation d’itérateurs et à produire un code plus propre, lisible et maintenable.
Selon leurs fonctionnalités, les itérateurs du module itertools
peuvent être classés en plusieurs catégories :
#1. Itérateurs Infini
Ces itérateurs permettent de manipuler des séquences illimitées et d’exécuter des boucles sans fin, à moins d’une condition d’arrêt. Ils sont particulièrement utiles pour simuler des boucles infinies ou pour générer des séquences sans limite. itertools
propose trois itérateurs infinis : count()
, cycle()
et repeat()
.
#2. Itérateurs Combinatoires
Les itérateurs combinatoires regroupent des fonctions destinées à travailler sur les produits cartésiens et à effectuer des combinaisons et des permutations d’éléments d’un itérable. Ils sont indispensables pour explorer toutes les manières possibles d’organiser ou de combiner des éléments. itertools
comprend quatre itérateurs combinatoires : product()
, permutations()
, combinations()
et combinations_with_replacement()
.
#3. Itérateurs Terminant sur la Séquence d’Entrée la Plus Courte
Ces itérateurs, utilisés sur des séquences finies, produisent une sortie déterminée par la fonction utilisée. Parmi eux, on trouve : accumulate()
, chain()
, chain.from_iterable()
, compress()
, dropwhile()
, filterfalse()
, groupby()
, islice()
, pairwise()
, starmap()
, takewhile()
, tee()
et zip_longest()
.
Examinons le fonctionnement de ces différentes fonctions d’itertools
en fonction de leur catégorie :
Itérateurs Infini
Les trois itérateurs infinis sont :
#1. count()
La fonction count(start, step)
génère une séquence infinie de nombres en partant d’une valeur initiale. Elle accepte deux arguments optionnels : start
, qui définit la valeur de départ de la séquence, et step
, qui détermine la différence entre deux nombres consécutifs. La valeur de départ par défaut est 0, et le pas par défaut est 1.
import itertools # Compte à partir de 4, avec des pas de 2 for i in itertools.count(4, 2): # Condition pour arrêter la boucle et éviter l'itération infinie if i == 14: break else: print(i) # Affichage : 4, 6, 8, 10, 12
Résultat:
4 6 8 10 12
#2. cycle()
La fonction cycle(iterable)
reçoit un itérable en paramètre et parcourt cet itérable en permettant l’accès aux éléments dans l’ordre où ils apparaissent.
Par exemple, si on passe ["rouge", "vert", "jaune"]
à cycle()
, au premier cycle on aura accès à « rouge », au second à « vert », puis à « jaune ». Au quatrième cycle, comme tous les éléments ont été parcourus, on recommencera avec « rouge » et ainsi de suite sans fin.
Lorsque vous utilisez cycle()
, il est recommandé de stocker le résultat dans une variable pour créer un itérateur qui conserve son état. Cela garantit que le cycle ne redémarre pas à chaque itération, et vous permet d’accéder à l’élément suivant à chaque appel.
import itertools couleurs = ["rouge", "vert", "jaune"] # Passez les couleurs à cycle() cycle_couleurs = itertools.cycle(couleurs) print(cycle_couleurs) # Utilisation de range pour arrêter la boucle après 7 impressions # next() est utilisé pour obtenir l'élément suivant de l'itérateur for i in range(7): print(next(cycle_couleurs))
Résultat:
rouge vert jaune rouge vert jaune rouge
#3. repeat()
repeat(elem, n)
accepte deux paramètres : l’élément à répéter (elem
) et le nombre de répétitions (n
). L’élément peut être une valeur unique ou un itérable. Si n
n’est pas spécifié, l’élément sera répété indéfiniment.
import itertools for i in itertools.repeat(10, 3): print(i)
Résultat:
10 10 10
Itérateurs Combinatoires
Les itérateurs combinatoires comprennent:
#1. product()
product()
calcule le produit cartésien de l’itérable qui lui est donné. Si on a deux ensembles, par exemple x = {7,8} et y = {1,2,3}, le produit cartésien de x et y contiendra toutes les combinaisons possibles d’éléments de x et y, avec le premier élément venant de x et le second de y. Le produit cartésien de x et y sera alors [(7, 1), (7, 2), (7, 3), (8, 1), (8, 2), (8, 3)].
product()
prend un paramètre optionnel nommé repeat
qui permet de calculer le produit cartésien d’un itérable avec lui-même. repeat
spécifie le nombre de répétitions pour chaque élément des itérables d’entrée lors du calcul du produit cartésien.
Par exemple, product('ABCD', repeat=2)
donne des combinaisons telles que (‘A’, ‘A’), (‘A’, ‘B’), (‘A’, ‘C’), etc. Si repeat
est égal à 3, la fonction produira des combinaisons comme (‘A’, ‘A’, ‘A’), (‘A’, ‘A’, ‘B’), (‘A’, ‘A’, ‘C’), (‘A’, ‘A’, ‘D’), et ainsi de suite.
from itertools import product # product() avec l'argument optionnel repeat print("product() avec l'argument optionnel repeat ") print(list(product('ABC', repeat = 2))) # product sans repeat print("product() SANS argument optionnel repeat") print(list(product([7,8], [1,2,3])))
Résultat
product() avec l'argument optionnel repeat [('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'B'), ('B', 'C'), ('C', 'A'), ('C', 'B'), ('C', 'C')] product() SANS argument optionnel repeat [(7, 1), (7, 2), (7, 3), (8, 1), (8, 2), (8, 3)]
#2. permutations()
permutations(iterable, group_size)
renvoie toutes les permutations possibles de l’itérable passé en argument. Une permutation représente le nombre de manières dont les éléments d’un ensemble peuvent être ordonnés. permutations()
prend un argument optionnel group_size
. Si group_size
n’est pas spécifié, les permutations générées auront la même taille que la longueur de l’itérable passé à la fonction.
import itertools nombres = [1, 2, 3] permutations_taillees = list(itertools.permutations(nombres,2)) permutations_non_taillees = list(itertools.permutations(nombres)) print("Permutations avec une taille de 2") print(permutations_taillees) print("Permutations SANS argument de taille") print(permutations_non_taillees)
Résultat
Permutations avec une taille de 2 [(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)] Permutations SANS argument de taille [(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]
#3. combinations()
combinations(iterable, size)
retourne toutes les combinaisons possibles d’un itérable d’une longueur donnée à partir des éléments de l’itérable passé à la fonction. L’argument size
spécifie la taille de chaque combinaison.
Les résultats sont ordonnés. La combinaison diffère légèrement des permutations. Avec la permutation, l’ordre compte, mais avec la combinaison, l’ordre n’a pas d’importance. Par exemple, dans [A, B, C], il y a 6 permutations : AB, AC, BA, BC, CA, CB, mais seulement 3 combinaisons : AB, AC, BC.
import itertools nombres = [1, 2, 3,4] combinaison_taille2 = list(itertools.combinations(nombres,2)) combinaison_taille3 = list(itertools.combinations(nombres, 3)) print("Combinaisons avec une taille de 2") print(combinaison_taille2) print("Combinaisons avec une taille de 3") print(combinaison_taille3)
Résultat:
Combinaisons avec une taille de 2 [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] Combinaisons avec une taille de 3 [(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]
#4. combinations_with_replacement()
combinations_with_replacement(iterable, size)
génère toutes les combinaisons possibles d’un itérable d’une longueur donnée à partir de l’itérable passé à la fonction, tout en autorisant les éléments répétés dans les combinaisons de sortie. La taille détermine la taille des combinaisons générées.
Cette fonction diffère de combinations()
car elle donne des combinaisons où un élément peut être répété plusieurs fois. Par exemple, vous pouvez obtenir une combinaison comme (1,1), ce qui n’est pas possible avec combination()
.
import itertools nombres = [1, 2, 3,4] combinaison_taille2 = list(itertools.combinations_with_replacement(nombres,2)) print("Combinations_with_replacement => taille 2") print(combinaison_taille2)
Résultat
Combinations_with_replacement => taille 2 [(1, 1), (1, 2), (1, 3), (1, 4), (2, 2), (2, 3), (2, 4), (3, 3), (3, 4), (4, 4)]
Itérateurs Terminant
Cela comprend des itérateurs tels que :
#1. accumulate()
accumulate(iterable, fonction)
prend un itérable et un second argument optionnel qui est une fonction. Il renvoie ensuite le résultat cumulé de l’application de la fonction à chaque itération sur les éléments de l’itérable. Si aucune fonction n’est transmise, l’addition est effectuée et les résultats cumulés sont renvoyés.
import itertools import operator nombres = [1, 2, 3, 4, 5] # Accumuler la somme des nombres valeur_accumulee = itertools.accumulate(nombres) accumulation_multiplication = itertools.accumulate(nombres, operator.mul) print("Accumuler sans fonction") print(list(valeur_accumulee)) print("Accumuler avec multiplication") print(list(accumulation_multiplication))
Résultat:
Accumuler sans fonction [1, 3, 6, 10, 15] Accumuler avec multiplication [1, 2, 6, 24, 120]
#2. chain()
chain(iterable_1, iterable_2, ...)
prend plusieurs itérables et les chaîne en produisant un seul itérable contenant les valeurs des itérables passés à la fonction chain()
.
import itertools lettres = ['A', 'B', 'C', 'D'] nombres = [1, 2, 3] couleurs = ['rouge', 'vert', 'jaune'] # Chainer lettres et nombres iterable_chaine = list(itertools.chain(lettres, nombres, couleurs)) print(iterable_chaine)
Résultat:
['A', 'B', 'C', 'D', 1, 2, 3, 'rouge', 'vert', 'jaune']
#3. chain.from_iterable()
chain.from_iterable(iterable)
Cette fonction est semblable à chain()
. Cependant, elle diffère car elle ne prend qu’un seul itérable contenant des sous-itérables et les enchaîne.
import itertools lettres = ['A', 'B', 'C', 'D'] nombres = [1, 2, 3] couleurs = ['rouge', 'vert', 'jaune'] iterable = ['bonjour',couleurs, lettres, nombres] chaine = list(itertools.chain.from_iterable(iterable)) print(chaine)
Résultat:
['b', 'o', 'n', 'j', 'o', 'u', 'r', 'rouge', 'vert', 'jaune', 'A', 'B', 'C', 'D', 1, 2, 3]
#4. compress()
compress(data, selectors)
prend deux arguments : data
qui est un itérable, et selectors
qui est un itérable contenant des valeurs booléennes true
et false
. Les valeurs 1
et 0
peuvent également être utilisées comme alternatives aux valeurs booléennes true
et false
. compress()
filtre ensuite les données passées en utilisant les éléments correspondants transmis dans le sélecteur.
Les valeurs dans data
qui correspondent à la valeur true
ou 1
dans le sélecteur sont sélectionnées, tandis que celles qui correspondent à false
ou 0
sont ignorées. Si vous passez moins de booléens dans les sélecteurs que le nombre d’éléments dans les données, tous les éléments au-delà des booléens passés dans les sélecteurs sont ignorés.
import itertools # data a 10 elements data = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'] # passage de 9 éléments selecteur selectors = [True, False, 1, False, 0, 1, True, False, 1] # Selection des éléments dans les données selon selectors données_filtrées = list(itertools.compress(data, selectors)) print(données_filtrées)
Résultat:
['A', 'C', 'F', 'G', 'I']
#5. dropwhile()
dropwhile(fonction, séquence)
prend une fonction avec une condition qui renvoie vrai ou faux, et une séquence de valeurs. Il supprime ensuite toutes les valeurs jusqu’à ce que la condition transmise renvoie False
. Une fois que la condition renvoie false
, les autres éléments sont inclus dans ses résultats, qu’ils renvoient True
ou False
.
import itertools nombres = [1, 2, 3, 4, 5, 1, 6, 7, 2, 1, 8, 9, 0, 7] # Supprime les éléments jusqu'à ce que la condition passée soit False nombres_filtrés = list(itertools.dropwhile(lambda x: x < 5, nombres)) print(nombres_filtrés)
Résultat:
[5, 1, 6, 7, 2, 1, 8, 9, 0, 7]
#6. filterfalse()
filterfalse(fonction, séquence)
prend une fonction avec une condition qui évalue vrai ou faux, et une séquence. Il renvoie ensuite les valeurs de la séquence qui ne satisfont pas la condition de la fonction.
import itertools nombres = [1, 2, 3, 4, 2, 3 ,5, 6, 5, 8, 1, 2, 3, 6, 2, 7, 4, 3] # Filtrer les éléments pour lesquels la condition est False nombres_filtrés = list(itertools.filterfalse(lambda x: x < 4, nombres)) print(nombres_filtrés)
Résultat:
[4, 5, 6, 5, 8, 6, 7, 4]
#7. groupby()
groupby(iterable, key)
prend un itérable et une clé, puis crée un itérateur qui renvoie des clés et des groupes consécutifs. Pour que cela fonctionne, l’itérable qui lui est transmis doit être trié sur la même fonction clé. La fonction clé calcule une valeur clé pour chaque élément de l’itérable.
import itertools liste_entree = [("Domestique", "Vache"), ("Domestique", "Chien"), ("Domestique", "Chat"),("Sauvage", "Lion"), ("Sauvage", "Zèbre"), ("Sauvage", "Éléphant")] classification = itertools.groupby(liste_entree,lambda x: x[0]) for cle,valeur in classification: print(cle,":",list(valeur))
Résultat:
Domestique : [('Domestique', 'Vache'), ('Domestique', 'Chien'), ('Domestique', 'Chat')] Sauvage : [('Sauvage', 'Lion'), ('Sauvage', 'Zèbre'), ('Sauvage', 'Éléphant')]
#8. islice()
islice(iterable, start, stop, step)
vous permet de découper un itérable en utilisant les valeurs start
, stop
et step
passées. L’argument step
est facultatif. Le comptage commence à partir de 0 et l’élément au numéro d’arrêt n’est pas inclus.
import itertools nombres = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18] # Sélectionne les éléments dans un intervalle nombres_selectionnés = list(itertools.islice(nombres, 2, 10)) nombres_selectionnés_pas = list(itertools.islice(nombres, 2, 10,2)) print("islice sans définir de valeur de pas") print(nombres_selectionnés) print("islice avec une valeur de pas de 2") print(nombres_selectionnés_pas)
Résultat:
islice sans définir de valeur de pas [3, 4, 5, 6, 7, 8, 9, 10] islice avec une valeur de pas de 2 [3, 5, 7, 9]
#9. pairwise()
pairwise(iterable)
renvoie des paires superposées successives extraites de l’itérable passé dans l’ordre dans lequel elles apparaissent dans l’itérable. Si l’itérable passé a moins de deux valeurs, le résultat de pairwise()
sera vide.
from itertools import pairwise nombres = [1, 2, 3, 4, 5, 6, 7, 8] mot = 'MONDE' unique = ['A'] print(list(pairwise(nombres))) print(list(pairwise(mot))) print(list(pairwise(unique)))
Résultat:
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8)] [('M', 'O'), ('O', 'N'), ('N', 'D'), ('D', 'E')] []
#10. starmap()
starmap(fonction, iterable)
est une fonction utilisée à la place de map()
lorsque les paramètres d’argument sont déjà regroupés en tuples. startmap()
applique une fonction aux éléments de l’itérable passé. L’itérable doit avoir des éléments regroupés en tuples.
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)))
Résultat:
[13, 5, 9, 16, 11]
#11. takewhile()
takewhile(function, iterable)
fonctionne à l’opposé de dropwhile()
. takewhile()
prend une fonction avec une condition à évaluer et un itérable. Il inclut ensuite tous les éléments de l’itérable qui satisfont la condition dans la fonction jusqu’à ce que False
soit renvoyé. Une fois que False
est renvoyé, tous les éléments suivants de l’itérable sont ignorés.
import itertools nombres = [1, 2, 3, 4, 5, 1, 6, 7, 2, 1, 8, 9, 0, 7] # Sélectionne les éléments jusqu'à ce que la condition passée soit False nombres_filtrés = list(itertools.takewhile(lambda x: x < 5, nombres)) print(nombres_filtrés)
Résultat:
[1, 2, 3, 4]
#12. tee()
tee(iterable, n)
prend un itérable et renvoie plusieurs itérateurs indépendants. Le nombre d’itérateurs à renvoyer est défini par n
, qui par défaut est 2.
import itertools nombres = [1, 2, 3, 4, 5] # Créer deux itérateurs indépendants à partir des nombres iter1, iter2 = itertools.tee(nombres, 2) print(list(iter1)) print(list(iter2))
Résultat:
[1, 2, 3, 4, 5] [1, 2, 3, 4, 5]
#13. zip_longest()
zip_longest(iterables, fillvalue)
accepte plusieurs itérateurs et une valeur de remplissage. Il retourne ensuite un itérateur qui regroupe les éléments de chacun des itérateurs qui lui sont passés. Si les itérateurs ne sont pas de la même longueur, les valeurs manquantes sont remplacées par la fillvalue
passée à la fonction jusqu’à épuisement de l’itérable le plus long.
import itertools noms = ['Jean', 'Mathieu', 'Marie', 'Alice', 'Bob', 'Charlie', 'Fury'] ages = [25, 30, 12, 13, 42] # Combiner les noms et âges, en remplissant les âges manquants avec un tiret combiné = itertools.zip_longest(noms, ages, fillvalue="-") for nom, age in combined: print(nom, age)
Résultat:
Jean 25 Mathieu 30 Marie 12 Alice 13 Bob 42 Charlie - Fury -
Conclusion
Les itertools
de Python sont un ensemble d’outils essentiel pour tout développeur Python. Ils sont largement utilisés dans la programmation fonctionnelle, le traitement et la transformation de données, le filtrage et la sélection de données, le regroupement et l’agrégation, la combinaison d’itérables, la combinatoire et la manipulation de séquences infinies.
En tant que développeur Python, vous tirerez un grand avantage de l’apprentissage des itertools
. Utilisez cet article pour vous familiariser avec ce module puissant.