Je n'ai trouvé aucun exemple valable sur Internet où je puisse voir la différence et pourquoi choisir l'un par rapport à l'autre.
Le premier prend 0 ou plusieurs arguments, chacun un itératif, le second prend un argument qui devrait produire les itérables:
itertools.chain(list1, list2, list3)
iterables = [list1, list2, list3]
itertools.chain.from_iterable(iterables)
mais iterables
peut être n’importe quel itérateur qui donne les itérables.
def generate_iterables():
for i in range(10):
yield range(i)
itertools.chain.from_iterable(generate_iterables())
L'utilisation de la seconde forme est généralement un cas de commodité, mais comme elle parcourt les iterables en entrée, c'est aussi le seul moyen de chaîner un nombre infinite d'itérateurs finis:
def generate_iterables():
while True:
for i in range(5, 10):
yield range(i)
itertools.chain.from_iterable(generate_iterables())
L'exemple ci-dessus vous donnera une valeur itérable qui produit un motif cyclique de nombres qui ne s'arrêteront jamais, mais ne consommeront jamais plus de mémoire que ce qu'un simple appel range()
nécessite.
Ils font des choses très similaires. itertools.chain(*iterables)
et itertools.chain.from_iterable(iterables)
fonctionnent de manière similaire pour un petit nombre de iterables.
Le principal avantage de from_iterables
réside dans la possibilité de gérer un grand nombre (potentiellement infini) de données itérables, car elles ne doivent pas toutes être disponibles au moment de l'appel.
Une autre façon de le voir:
chain(iterable1, iterable2, iterable3, ...)
est pour quand vous savez déjà quels iterables vous avez, ainsi vous pouvez les écrire en tant que ces arguments séparés par des virgules.
chain.from_iterable(iterable)
est pour quand vos iterables (comme iterable1, iterable2, iterable3) sont obtenus à partir d'un autre iterable.
Je n'ai trouvé aucun exemple valide ... où je peux voir la différence entre eux [
chain
etchain.from_iterable
] et pourquoi choisir l'un plutôt que l'autre
La réponse acceptée est approfondie. Pour ceux qui recherchent une application rapide, envisagez d’aplatir plusieurs listes:
list(itertools.chain(["a", "b", "c"], ["d", "e"], ["f"]))
# ['a', 'b', 'c', 'd', 'e', 'f']
Vous souhaiterez peut-être réutiliser ces listes ultérieurement, de sorte que vous en fassiez une liste:
iterable = (["a", "b", "c"], ["d", "e"], ["f"])
Tentative
Cependant, le passage d'un itératif à chain
donne un résultat non aplati:
list(itertools.chain(iterable))
# [['a', 'b', 'c'], ['d', 'e'], ['f']]
Pourquoi? Vous avez passé dans un élément one (un tuple). chain
a besoin de chaque liste séparément.
Solutions
Lorsque cela est possible, vous pouvez décompresser un itérable:
list(itertools.chain(*iterable))
# ['a', 'b', 'c', 'd', 'e', 'f']
list(itertools.chain(*iter(iterable)))
# ['a', 'b', 'c', 'd', 'e', 'f']
Plus généralement, utilisez .from_iterable
(car cela fonctionne aussi avec des itérateurs infinis):
list(itertools.chain.from_iterable(iterable))
# ['a', 'b', 'c', 'd', 'e', 'f']
g = itertools.chain.from_iterable(itertools.cycle(iterable))
next(g)
# "a"