Tengo una lista de tuplas de 2 elementos y me gustaría convertirlas en 2 listas donde la primera contiene el primer elemento en cada tupla y la segunda lista contiene el segundo elemento.
Por ejemplo:
original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
# and I want to become...
result = (['a', 'b', 'c', 'd'], [1, 2, 3, 4])
¿Hay una función integrada que hace eso?

Respuestas:
zipes su propio inverso! Siempre que utilice el operador especial *.La forma en que esto funciona es llamando
zipcon los argumentos:... excepto que los argumentos se pasan
zipdirectamente (después de convertirse en una tupla), por lo que no hay necesidad de preocuparse por el número de argumentos que se hacen demasiado grandes.fuente
zip([], [])esta manera no te atrapa[], []. Le consigue[]. Si solo ...zipfunciona exactamente igual en Python 3, excepto que devuelve un iterador en lugar de una lista. Para obtener el mismo resultado que el anterior, solo necesita incluir la llamada zip en una lista:list(zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)]))generará[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]lists están bien. Pero si intenta obtener el resultado completo de una sola vez (silistaplica el resultado dezip), podría usar mucha memoria (porque todos lostuples deben crearse a la vez). Si solo puede iterar sobre el resultadozipsinlistifying, ahorrará mucha memoria. La única otra preocupación es si la entrada tiene muchos elementos; el costo es que debe desempaquetarlos a todos como argumentos yzipnecesitará crear y almacenar iteradores para todos ellos. Esto es solo un problema real con s muy largoslist(piense en cientos de miles de elementos o más).También podrías hacer
se debe escalar mejor. Especialmente si Python hace bien en no expandir las comprensiones de la lista a menos que sea necesario.
(Por cierto, hace una lista de 2 tuplas (par), en lugar de una lista de tuplas, como
ziphace).Si los generadores en lugar de las listas reales están bien, esto haría eso:
Los generadores no se mueven a través de la lista hasta que solicite cada elemento, pero por otro lado, mantienen referencias a la lista original.
fuente
zip(*x)versión.zip(*x)solo requiere una pasada a través del bucle y no utiliza elementos de la pila.zipsi el caso de uso es que los datos transpuestos se usan y descartan de inmediato, mientras que las listas originales permanecen en la memoria por mucho más tiempo.Si tiene listas que no tienen la misma longitud, es posible que no desee usar zip según la respuesta de Patricks. Esto funciona:
Pero con diferentes listas de longitud, zip trunca cada elemento a la longitud de la lista más corta:
Puede usar el mapa sin función para llenar resultados vacíos con Ninguno:
zip () es marginalmente más rápido sin embargo.
fuente
izip_longestzip_longestpara los usuarios de python3.Me gusta usar
zip(*iterable)(que es el código que estás buscando) en mis programas así:Me parece
unzipmás legible.fuente
Da una tupla de listas como en la pregunta.
Descomprime las dos listas.
fuente
Enfoque ingenuo
funciona bien para iterables finitos (por ejemplo, secuencias como
list/tuple/str) de iterables (potencialmente infinitos) que pueden ilustrarse comodónde
n in ℕ,a_ijcorresponde aljelementoi-th de -th iterable,y después de aplicar
transpose_finite_iterableobtenemosEjemplo de Python de tal caso donde
a_ij == j,n == 2Pero no podemos usar
transpose_finite_iterablenuevamente para volver a la estructura del originaliterableporqueresultes un iterable infinito de iterables finitos (tuples en nuestro caso):Entonces, ¿cómo podemos lidiar con este caso?
... y aquí viene el
dequeDespués de echar un vistazo a los documentos de
itertools.teefunción , hay una receta de Python que con alguna modificación puede ayudar en nuestro casovamos a revisar
Síntesis
Ahora podemos definir la función general para trabajar con iterables de iterables, de los cuales son finitos y otros potencialmente infinitos usando
functools.singledispatchdecorador comoque puede considerarse como su propio inverso (los matemáticos llaman a este tipo de funciones "involuciones" ) en la clase de operadores binarios sobre iterables finitos no vacíos.
Como beneficio adicional
singledispatch, podemos manejarnumpymatrices comoy luego úsalo como
Nota
Desde
transposedevuelve iteradores y si alguien quiere tener unatupledelists como en la OP - esto se puede hacer, además, con lamapfunción incorporada comoAnuncio
He agregado una solución generalizada al
lzpaquete desde la0.5.0versión que se puede usar comoPD
No hay una solución (al menos obvia) para manejar iterables potencialmente infinitos de iterables potencialmente infinitos, pero este caso es menos común.
fuente
Es solo otra forma de hacerlo, pero me ayudó mucho, así que lo escribo aquí:
Teniendo esta estructura de datos:
Resultando en:
La forma más pitónica de descomprimirlo y volver al original es esta en mi opinión:
Pero esto devuelve una tupla, por lo que si necesita una lista puede usar:
fuente
Considere usar more_itertools.unzip :
fuente
Como devuelve tuplas (y puede usar toneladas de memoria), el
zip(*zipped)truco me parece más inteligente que útil.Aquí hay una función que realmente le dará la inversa de zip.
fuente
Ninguna de las respuestas anteriores proporciona eficientemente el resultado requerido, que es una tupla de listas , en lugar de una lista de tuplas . Para el primero, puedes usar
tupleconmap. Aquí está la diferencia:Además, la mayoría de las soluciones anteriores suponen Python 2.7, donde
zipdevuelve una lista en lugar de un iterador.Para Python 3.x, deberá pasar el resultado a una función como
listotupleagotar el iterador. Para los iteradores con uso eficiente de la memoria, puede omitir el exteriorlistytuplesolicitar las soluciones respectivas.fuente
Mientras
zip(*seq)es muy útil, puede no ser adecuado para secuencias muy largas, ya que creará una tupla de valores para pasar. Por ejemplo, he estado trabajando con un sistema de coordenadas con más de un millón de entradas y creo que es mucho más rápido crear Las secuencias directamente.Un enfoque genérico sería algo como esto:
Pero, dependiendo de lo que quiera hacer con el resultado, la elección de la colección puede marcar una gran diferencia. En mi caso de uso real, el uso de conjuntos y sin bucle interno es notablemente más rápido que todos los demás enfoques.
Y, como otros han señalado, si está haciendo esto con conjuntos de datos, podría tener sentido usar colecciones de Numpy o Pandas.
fuente
Si bien las matrices y pandas numpy pueden ser preferibles, esta función imita el comportamiento de
zip(*args)cuando se llama comounzip(args).Permite que los generadores se pasen a
argsmedida que itera por los valores. Decorarclsy / omain_clsmicro gestionar la inicialización del contenedor.fuente