J'ai une liste de tuples à 2 éléments et je voudrais les convertir en 2 listes où le premier contient le premier élément dans chaque tuple et la deuxième liste contient le deuxième élément.
Par exemple:
original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
# and I want to become...
result = (['a', 'b', 'c', 'd'], [1, 2, 3, 4])
Y a-t-il une fonction intégrée qui fait cela?
Réponses:
zip
est son propre inverse! À condition d'utiliser l'opérateur spécial *.La façon dont cela fonctionne est en appelant
zip
avec les arguments:… Sauf que les arguments sont passés
zip
directement (après avoir été convertis en tuple), il n'y a donc pas lieu de s'inquiéter du nombre d'arguments trop volumineux.la source
zip([], [])
cette façon ne vous permet pas[], []
. Ça vous prend[]
. Si seulement ...zip
fonctionne exactement de la même manière dans Python 3, sauf qu'il renvoie un itérateur au lieu d'une liste. Afin d'obtenir la même sortie que ci-dessus, vous avez juste besoin d'envelopper l'appel zip dans une liste:list(zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)]))
affichera[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]
list
bien. Mais si vous essayez de réaliser le résultat complet en une seule fois (enlist
imitant le résultat dezip
), vous pouvez utiliser beaucoup de mémoire (car tous lestuple
s doivent être créés en même temps). Si vous pouvez simplement répéter le résultat dezip
sanslist
ifying, vous économiserez beaucoup de mémoire. La seule autre préoccupation est de savoir si l'entrée comporte de nombreux éléments; le coût est qu'il doit les déballer tous comme arguments, etzip
devra créer et stocker des itérateurs pour chacun d'eux. Ce n'est qu'un vrai problème avec deslist
s très longs (pensez à des centaines de milliers d'éléments ou plus).Vous pourriez aussi faire
Il devrait mieux évoluer. Surtout si Python fait bien de ne pas étendre les compréhensions de liste à moins que cela ne soit nécessaire.
(Incidemment, cela fait une liste de 2 tuple (paire), plutôt qu'une liste de tuples, comme le
zip
fait.)Si les générateurs au lieu des listes réelles sont corrects, cela ferait cela:
Les générateurs ne parcourent pas la liste jusqu'à ce que vous demandiez chaque élément, mais d'un autre côté, ils gardent les références à la liste d'origine.
la source
zip(*x)
version.zip(*x)
ne nécessite qu'un seul passage dans la boucle et n'utilise pas les éléments de pile.zip
si le cas d'utilisation est que les données transposées sont utilisées et rejetées immédiatement, tandis que les listes originales restent en mémoire beaucoup plus longtemps.Si vous avez des listes qui ne sont pas de la même longueur, vous ne voudrez peut-être pas utiliser zip comme indiqué dans la réponse de Patrick. Cela marche:
Mais avec des listes de longueurs différentes, zip tronque chaque élément à la longueur de la liste la plus courte:
Vous pouvez utiliser la carte sans fonction pour remplir les résultats vides avec Aucun:
zip () est cependant légèrement plus rapide.
la source
izip_longest
zip_longest
pour les utilisateurs de python3.J'aime utiliser
zip(*iterable)
(qui est le morceau de code que vous recherchez) dans mes programmes comme suit:Je trouve
unzip
plus lisible.la source
Donne un tuple de listes comme dans la question.
Décompresse les deux listes.
la source
Approche naïve
fonctionne très bien pour des itérables finis (par exemple des séquences comme
list
/tuple
/str
) d'itérables (potentiellement infinis) qui peuvent être illustrés commeoù
n in ℕ
,a_ij
correspond auj
-ème élément dui
-ème itérable,et après avoir appliqué,
transpose_finite_iterable
nous obtenonsExemple Python d'un tel cas où
a_ij == j
,n == 2
Mais nous ne pouvons pas utiliser à
transpose_finite_iterable
nouveau pour revenir à la structure de l'originaliterable
car ilresult
s'agit d'un itérable infini d'itérables finis (tuple
s dans notre cas):Alors, comment pouvons-nous traiter ce cas?
... et voici
deque
Après avoir regardé les documents de
itertools.tee
fonction , il existe une recette Python qui, avec quelques modifications, peut aider dans notre casAllons vérifier
Synthèse
Maintenant, nous pouvons définir une fonction générale pour travailler avec des itérables dont certains sont finis et d'autres potentiellement infinis en utilisant un
functools.singledispatch
décorateur commequi peut être considérée comme son propre inverse (les mathématiciens appellent ce type de fonctions "involutions" ) dans la classe des opérateurs binaires sur des itérables finis non vides.
En prime,
singledispatch
nous pouvons gérer desnumpy
tableaux commepuis l'utiliser comme
Remarque
Depuis
transpose
retourne les itérateurs et si quelqu'un veut avoir untuple
delist
s comme dans OP - cela peut être fait en plus avec unemap
fonction intégrée commePublicité
J'ai ajouté une solution généralisée au
lz
package à partir de la0.5.0
version qui peut être utilisée commePS
Il n'y a pas de solution (du moins évidente) pour gérer les itérables potentiellement infinis des itérables potentiellement infinis, mais ce cas est cependant moins courant.
la source
Ce n'est qu'une autre façon de le faire, mais cela m'a beaucoup aidé, alors je l'écris ici:
Ayant cette structure de données:
Résultant en:
La façon la plus pythonique de le décompresser et de revenir à l'original est celle-ci à mon avis:
Mais cela retourne un tuple donc si vous avez besoin d'une liste, vous pouvez utiliser:
la source
Pensez à utiliser more_itertools.unzip :
la source
Puisqu'il renvoie des tuples (et peut utiliser des tonnes de mémoire), l'
zip(*zipped)
astuce me semble plus intelligente qu'utile.Voici une fonction qui vous donnera en fait l'inverse de zip.
la source
Aucune des réponses précédentes ne fournit efficacement la sortie requise, qui est un tuple de listes , plutôt qu'une liste de tuples . Pour les premiers, vous pouvez utiliser
tuple
avecmap
. Voici la différence:De plus, la plupart des solutions précédentes supposent Python 2.7, où
zip
renvoie une liste plutôt qu'un itérateur.Pour Python 3.x, vous devrez passer le résultat à une fonction telle que
list
outuple
pour épuiser l'itérateur. Pour les itérateurs économes en mémoire, vous pouvez omettre l'extérieurlist
ettuple
appeler les solutions respectives.la source
Bien qu'il
zip(*seq)
soit très utile, il peut ne pas convenir à de très longues séquences car il créera un tuple de valeurs à transmettre. Par exemple, j'ai travaillé avec un système de coordonnées avec plus d'un million d'entrées et je le trouve beaucoup plus rapide à créer directement les séquences.Une approche générique serait quelque chose comme ceci:
Mais, selon ce que vous voulez faire du résultat, le choix de la collection peut faire une grande différence. Dans mon cas d'utilisation réel, l'utilisation d'ensembles et sans boucle interne est sensiblement plus rapide que toutes les autres approches.
Et, comme d'autres l'ont noté, si vous faites cela avec des ensembles de données, il peut être judicieux d'utiliser à la place des collections Numpy ou Pandas.
la source
Alors que les tableaux et les pandas engourdis peuvent être préférables, cette fonction imite le comportement de
zip(*args)
lorsqu'il est appelé asunzip(args)
.Permet aux générateurs d'être transmis au
args
fur et à mesure de l'itération des valeurs. Décorezcls
et / oumain_cls
microgérez l'initialisation du conteneur.la source