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:
zip
es su propio inverso! Siempre que utilice el operador especial *.La forma en que esto funciona es llamando
zip
con los argumentos:... excepto que los argumentos se pasan
zip
directamente (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 ...zip
funciona 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)]
list
s están bien. Pero si intenta obtener el resultado completo de una sola vez (silist
aplica el resultado dezip
), podría usar mucha memoria (porque todos lostuple
s deben crearse a la vez). Si solo puede iterar sobre el resultadozip
sinlist
ifying, 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 yzip
necesitará 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
zip
hace).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.zip
si 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_longest
zip_longest
para los usuarios de python3.Me gusta usar
zip(*iterable)
(que es el código que estás buscando) en mis programas así:Me parece
unzip
má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_ij
corresponde alj
elementoi
-th de -th iterable,y después de aplicar
transpose_finite_iterable
obtenemosEjemplo de Python de tal caso donde
a_ij == j
,n == 2
Pero no podemos usar
transpose_finite_iterable
nuevamente para volver a la estructura del originaliterable
porqueresult
es un iterable infinito de iterables finitos (tuple
s en nuestro caso):Entonces, ¿cómo podemos lidiar con este caso?
... y aquí viene el
deque
Después de echar un vistazo a los documentos de
itertools.tee
funció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.singledispatch
decorador 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 manejarnumpy
matrices comoy luego úsalo como
Nota
Desde
transpose
devuelve iteradores y si alguien quiere tener unatuple
delist
s como en la OP - esto se puede hacer, además, con lamap
función incorporada comoAnuncio
He agregado una solución generalizada al
lz
paquete desde la0.5.0
versió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
tuple
conmap
. Aquí está la diferencia:Además, la mayoría de las soluciones anteriores suponen Python 2.7, donde
zip
devuelve una lista en lugar de un iterador.Para Python 3.x, deberá pasar el resultado a una función como
list
otuple
agotar el iterador. Para los iteradores con uso eficiente de la memoria, puede omitir el exteriorlist
ytuple
solicitar 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
args
medida que itera por los valores. Decorarcls
y / omain_cls
micro gestionar la inicialización del contenedor.fuente