Cette version de flatten
évite la limite de récursion de python (et fonctionne donc avec des itérables imbriqués et arbitrairement profonds). C'est un générateur qui peut gérer des chaînes de caractères et des itérables arbitraires (même infinis).
import itertools as IT
import collections
def flatten(iterable, ltypes=collections.Iterable):
remainder = iter(iterable)
while True:
first = next(remainder)
if isinstance(first, ltypes) and not isinstance(first, (str, bytes)):
remainder = IT.chain(first, remainder)
else:
yield first
Voici quelques exemples démontrant son utilisation :
print(list(IT.islice(flatten(IT.repeat(1)),10)))
# [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
print(list(IT.islice(flatten(IT.chain(IT.repeat(2,3),
{10,20,30},
'foo bar'.split(),
IT.repeat(1),)),10)))
# [2, 2, 2, 10, 20, 30, 'foo', 'bar', 1, 1]
print(list(flatten([[1,2,[3,4]]])))
# [1, 2, 3, 4]
seq = ([[chr(i),chr(i-32)] for i in range(ord('a'), ord('z')+1)] + list(range(0,9)))
print(list(flatten(seq)))
# ['a', 'A', 'b', 'B', 'c', 'C', 'd', 'D', 'e', 'E', 'f', 'F', 'g', 'G', 'h', 'H',
# 'i', 'I', 'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N', 'o', 'O', 'p', 'P',
# 'q', 'Q', 'r', 'R', 's', 'S', 't', 'T', 'u', 'U', 'v', 'V', 'w', 'W', 'x', 'X',
# 'y', 'Y', 'z', 'Z', 0, 1, 2, 3, 4, 5, 6, 7, 8]
Bien que flatten
peut gérer les générateurs infinis, mais pas l'imbrication infinie :
def infinitely_nested():
while True:
yield IT.chain(infinitely_nested(), IT.repeat(1))
print(list(IT.islice(flatten(infinitely_nested()), 10)))
# hangs
34 votes
Le fait qu'il y ait autant de réponses et autant d'actions sur cette question suggère vraiment que cela devrait être une fonction intégrée quelque part, non ? Il est particulièrement dommage que compiler.ast ait été supprimé de Python 3.0.
3 votes
Je dirais que ce dont Python a vraiment besoin, c'est d'une récursion ininterrompue plutôt que d'un autre buildin.
4 votes
@Mittenchops : totalement en désaccord, le fait que les personnes travaillant avec des API manifestement mauvaises/des structures de données trop compliquées (juste une note :
list
est censé être homogène) ne signifie pas que c'est la faute de Python et que nous avons besoin d'un buildin pour cette tâche.7 votes
Si vous pouvez vous permettre d'ajouter un paquet à votre projet - je suppose que la more_itertools.collapse La solution la mieux adaptée. De cette réponse : stackoverflow.com/a/40938883/3844376
0 votes
@viddik13 : pensez à en faire une réponse à cette question également. Je l'upvoterais sans hésiter. (Je suis d'accord avec Mittenchops.) Le fait qu'il ne s'agisse pas d'une intégré est très bien (concernant Azat Ibrakov), mais il devrait y avoir (et, apparemment, il y a !) une routine de bibliothèque pour faire cela. (Parce que : tous les irrégularité est "mauvais"/"trop compliqué". Parfois, c'est juste... non régulier et ce n'est pas grave. IMHO. Tant que ce qu'il est est bien défini, et il peut l'être, et être encore irrégulier ("une liste (de listes (de listes...)) d'entiers arbitrairement imbriquée", par exemple, est bien défini).