Zip con salida de lista en lugar de tupla

94

¿Cuál es la forma más rápida y elegante de hacer listas de listas de dos listas?

yo tengo

In [1]: a=[1,2,3,4,5,6]

In [2]: b=[7,8,9,10,11,12]

In [3]: zip(a,b)
Out[3]: [(1, 7), (2, 8), (3, 9), (4, 10), (5, 11), (6, 12)]

Y me gustaría tener

In [3]: some_method(a,b)
Out[3]: [[1, 7], [2, 8], [3, 9], [4, 10], [5, 11], [6, 12]]

Estaba pensando en usar map en lugar de zip, pero no sé si hay algún método de biblioteca estándar para poner como primer argumento.

Puedo definir mi propia función para esto y usar el mapa, mi pregunta es si ya hay algo implementado. No también es una respuesta.

Jan Vorcak
fuente
1
Bueno, ¿realmente necesitas listas? ¿Qué vas a hacer con los resultados?
Karl Knechtel
14
Un ejemplo sería sklearn, donde muchas veces los datos deben organizarse de esta manera.
tumultous_rooster

Respuestas:

101

Si está comprimiendo más de 2 listas (o incluso solo 2, para el caso), una forma legible sería:

[list(a) for a in zip([1,2,3], [4,5,6], [7,8,9])]

Esto utiliza listas por comprensión y convierte cada elemento de la lista (tuplas) en listas.

DK
fuente
54

Casi tienes la respuesta tú mismo. No use en maplugar de zip. Utilice map AND zip .

Puede usar mapa junto con zip para un enfoque elegante y funcional:

list(map(list, zip(a, b)))

zipdevuelve una lista de tuplas. map(list, [...])llama lista cada tupla de la lista. list(map([...])convierte el objeto del mapa en una lista legible.

Eldamir
fuente
la desafortunada decisión de hacer que las operaciones de recopilación de Python 3 devuelvan a generatorimpone el costo del doble listaquí.
StephenBoesch
15

Me encanta la elegancia de la función zip, pero el uso de la función itemgetter () en el módulo del operador parece ser mucho más rápido. Escribí un script simple para probar esto:

import time
from operator import itemgetter

list1 = list()
list2 = list()
origlist = list()
for i in range (1,5000000):
        t = (i, 2*i)
        origlist.append(t)

print "Using zip"
starttime = time.time()
list1, list2 = map(list, zip(*origlist))
elapsed = time.time()-starttime
print elapsed

print "Using itemgetter"
starttime = time.time()
list1 = map(itemgetter(0),origlist)
list2 = map(itemgetter(1),origlist)
elapsed = time.time()-starttime
print elapsed

Esperaba que zip fuera más rápido, pero el método itemgetter gana por mucho:

Using zip
6.1550450325
Using itemgetter
0.768098831177
kslnet
fuente
2
Esta es una transposición de lo que el OP está tratando de hacer. ¿Podrías actualizar tu publicación para reflejar eso? Es decir, OP está convirtiendo dos listas en una lista o un número arbitrario de pares. Estás convirtiendo un número arbitrario de pares en un par de listas.
Mad Physicist
¿Con qué versión de Python se mide esto?
Moberg
No recuerdo, fue hace más de dos años, pero probablemente 2.6 o 2.7. Imagino que puedes copiar el código y probarlo en tu propia versión / plataforma.
kslnet
2
python 2 zipcrea una lista real. Eso ralentiza las cosas. Intente reemplazar zipcon itertools.izipentonces.
Jean-François Fabre
En Python 3.5, zip tarda 3,5 segundos y itemgetter, 0,10 segundos. Para los amantes de la comprensión de listas, list1 = [x[0] for x in origlist]funciona tan bien como list1 = map(itemgetter(0), origlist).
Elias Strehle
3

Generalmente no me gusta usar lambda, pero ...

>>> a = [1, 2, 3, 4, 5]
>>> b = [6, 7, 8, 9, 10]
>>> c = lambda a, b: [list(c) for c in zip(a, b)]
>>> c(a, b)
[[1, 6], [2, 7], [3, 8], [4, 9], [5, 10]]

Si necesita la velocidad adicional, el mapa es un poco más rápido:

>>> d = lambda a, b: map(list, zip(a, b))
>>> d(a, b)
[[1, 6], [2, 7], [3, 8], [4, 9], [5, 10]]

Sin embargo, el mapa se considera no pitónico y solo debe usarse para ajustar el rendimiento.

Ceasar Bautista
fuente
4
¿Qué lambdaagrega aquí? Uno puede simplemente escribir la expresión en lugar de llamar a una función (realmente no es complicado), e incluso si uno quiere una función para ello, se puede definir sin dolor en dos líneas (una si su tecla de retorno está rota o está loco) . mappor otro lado, está perfectamente bien si el primer argumento fuera una función simple (a diferencia de a lambda).
1
Bueno, pidió una función. Pero estoy de acuerdo, probablemente sea mejor pagar la línea extra. En cuanto al mapa, creo que las listas por comprensión son casi siempre más claras.
Ceasar Bautista
1
Recomendaría mapmás lambda. así map(list, zip(a,b)). Las listas por comprensión pueden ser un poco más claras, pero el mapa debería ser más rápido (no probado)
inspectorG4dget
Quiero decir, nuevamente, si el OP necesita velocidad, el mapa es el camino a seguir. Pero en general, y en Python especialmente, enfatice la legibilidad sobre la velocidad (de lo contrario, se sumerge en la optimización prematura).
Ceasar Bautista
3

¿Qué tal esto?

>>> def list_(*args): return list(args)

>>> map(list_, range(5), range(9,4,-1))
[[0, 9], [1, 8], [2, 7], [3, 6], [4, 5]]

O mejor:

>>> def zip_(*args): return map(list_, *args)
>>> zip_(range(5), range(9,4,-1))
[[0, 9], [1, 8], [2, 7], [3, 6], [4, 5]]
Broseph
fuente
Me parece una mejor respuesta que el resto, ya que aquí estamos reduciendo un paso al no hacer un zip y crear directamente una lista. Impresionante
Akshay Hazari
2

Usando numpy

La definición de elegancia puede ser bastante cuestionable, pero si está trabajando con numpyla creación de una matriz y su conversión a lista (si es necesario ...) podría ser muy práctica aunque no sea tan eficiente en comparación con la mapfunción o la comprensión de listas.

import numpy as np 
a = b = range(10)
zipped = zip(a,b)
result = np.array(zipped).tolist()
Out: [[0, 0],
 [1, 1],
 [2, 2],
 [3, 3],
 [4, 4],
 [5, 5],
 [6, 6],
 [7, 7],
 [8, 8],
 [9, 9]]

De lo contrario, puede omitir la zipfunción que puede usar directamente np.dstack:

np.dstack((a,b))[0].tolist()
GM
fuente
1

La comprensión de listas sería una solución muy simple, supongo.

a=[1,2,3,4,5,6]

b=[7,8,9,10,11,12]

x = [[i, j] for i, j in zip(a,b)]

print(x)

output : [[1, 7], [2, 8], [3, 9], [4, 10], [5, 11], [6, 12]]
axai_m
fuente