into - lista de conversión de Python al diccionario
python list to dict (4)
Esta pregunta ya tiene una respuesta aquí:
- Convertir una lista a un diccionario en Python 12 respuestas
l = ["a", "b", "c", "d", "e"]
Quiero convertir esta lista a un diccionario como:
d = {"a": "b", "c": "d", "e": ""}
Entonces, básicamente, los pares serán claves, mientras que las probabilidades serán valores. Sé que puedo hacerlo de una manera "no pitónica", como un bucle for con declaraciones if, pero creo que debería haber una forma más "pitónica" de lograr esto. Entonces, agradezco cualquier ayuda :)
Me gustaría recurrencias:
l = [''a'', ''b'', ''c'', ''d'', ''e'', '' '']
d = dict([(k, v) for k,v in zip (l[::2], l[1::2])])
No estoy seguro de si te ayudaría o no, pero me funciona:
l = ["a", "b", "c", "d", "e"]
outRes = dict((l[i], l[i+1]) if i+1 < len(l) else (l[i], '''') for i in xrange(len(l)))
Si todavía estás pensando qué! No estarías solo, en realidad no es tan complicado, déjame explicarte.
Cómo convertir una lista en un diccionario utilizando únicamente funciones incorporadas
Queremos convertir la siguiente lista en un diccionario utilizando las entradas impares (contando desde 1) como claves mapeadas a sus entradas pares consecutivas.
l = ["a", "b", "c", "d", "e"]
dict ()
Para crear un diccionario, podemos usar la función dict
incorporada para los tipos de mapeo según el manual. Los siguientes métodos son compatibles.
dict(one=1, two=2)
dict({''one'': 1, ''two'': 2})
dict(zip((''one'', ''two''), (1, 2)))
dict([[''two'', 2], [''one'', 1]])
La última opción sugiere que proporcionemos una lista de listas con 2 valores o tuplas (key, value)
, por lo que queremos convertir nuestra lista secuencial en:
l = [["a", "b"], ["c", "d"], ["e",]]
También se nos presenta la función zip
, una de las funciones integradas que explica el manual:
devuelve una lista de tuplas, donde la i-ésima tupla contiene el elemento i-ésimo de cada uno de los argumentos
En otras palabras, si podemos convertir nuestra lista en dos listas a, c, e
y b, d
, zip
hará el resto.
notación rebanada
Slicings que vemos usados con Strings y también más adelante en la sección de la Lista que utiliza principalmente el rango o la notación de corte corto, pero así es como se ve la notación de corte largo y lo que podemos lograr con el paso :
>>> l[::2]
[''a'', ''c'', ''e'']
>>> l[1::2]
[''b'', ''d'']
>>> zip([''a'', ''c'', ''e''], [''b'', ''d''])
[(''a'', ''b''), (''c'', ''d'')]
>>> dict(zip(l[::2], l[1::2]))
{''a'': ''b'', ''c'': ''d''}
A pesar de que esta es la forma más simple de entender la mecánica involucrada, hay un inconveniente porque las divisiones son nuevos objetos de lista cada vez, como se puede ver con este ejemplo de clonación:
>>> a = [1, 2, 3]
>>> b = a
>>> b
[1, 2, 3]
>>> b is a
True
>>> b = a[:]
>>> b
[1, 2, 3]
>>> b is a
False
Aunque b parece que son dos objetos separados ahora, es por eso que preferimos usar la receta del mero .
receta de mero
Aunque el mero se explica como parte del módulo itertools, funciona perfectamente bien con las funciones básicas también.
Un poco de vudú serio ¿verdad? =) Pero en realidad nada más que un poco de azúcar sintáctica para especias, la receta del mero se logra con la siguiente expresión.
*[iter(l)]*2
Que más o menos se traduce en dos argumentos del mismo iterador envueltos en una lista, si eso tiene algún sentido. Vamos a descomponerlo para ayudar a arrojar algo de luz.
zip para el más corto
>>> l*2
[''a'', ''b'', ''c'', ''d'', ''e'', ''a'', ''b'', ''c'', ''d'', ''e'']
>>> [l]*2
[[''a'', ''b'', ''c'', ''d'', ''e''], [''a'', ''b'', ''c'', ''d'', ''e'']]
>>> [iter(l)]*2
[<listiterator object at 0x100486450>, <listiterator object at 0x100486450>]
>>> zip([iter(l)]*2)
[(<listiterator object at 0x1004865d0>,),(<listiterator object at 0x1004865d0>,)]
>>> zip(*[iter(l)]*2)
[(''a'', ''b''), (''c'', ''d'')]
>>> dict(zip(*[iter(l)]*2))
{''a'': ''b'', ''c'': ''d''}
Como puede ver, las direcciones de los dos iteradores siguen siendo las mismas, así que estamos trabajando con el mismo iterador, de ahí que primero obtengamos una clave y luego un valor y una clave y un valor cada vez que pisemos el mismo iterador para lograr lo que hicimos con las rebanadas mucho más productivo.
Usted lograría mucho lo mismo con el siguiente que lleva un menor ¿Qué? factor tal vez.
>>> it = iter(l)
>>> dict(zip(it, it))
{''a'': ''b'', ''c'': ''d''}
¿Qué pasa con la clave vacía e
si se ha dado cuenta de que ha faltado en todos los ejemplos, porque zip
selecciona el más corto de los dos argumentos, entonces qué vamos a hacer?
Bueno, una solución podría ser agregar un valor vacío a las listas de longitud impar, puede optar por utilizar append
y una instrucción if
que haría el truco, aunque un poco aburrido, ¿verdad?
>>> if len(l) % 2:
... l.append("")
>>> l
[''a'', ''b'', ''c'', ''d'', ''e'', '''']
>>> dict(zip(*[iter(l)]*2))
{''a'': ''b'', ''c'': ''d'', ''e'': ''''}
Ahora, antes de encogerse de hombros para ir a escribir from itertools import izip_longest
, puede que se sorprenda al saber que no es necesario, podemos lograr lo mismo, incluso mejor en mi humilde opinión, con las funciones integradas por sí solas.
mapa para el más largo
Prefiero usar la función map () en lugar de izip_longest() que no solo usa una sintaxis más corta, no requiere una importación, sino que puede asignar un valor de None
vacío cuando sea necesario, automágicamente.
>>> l = ["a", "b", "c", "d", "e"]
>>> l
[''a'', ''b'', ''c'', ''d'', ''e'']
>>> dict(map(None, *[iter(l)]*2))
{''a'': ''b'', ''c'': ''d'', ''e'': None}
Comparando el rendimiento de los dos métodos, como señala KursedMetal, está claro que el módulo itertools supera con creces la función de mapa en grandes volúmenes, como lo muestra un punto de referencia frente a 10 millones de registros.
$ time python -c ''dict(map(None, *[iter(range(10000000))]*2))''
real 0m3.755s
user 0m2.815s
sys 0m0.869s
$ time python -c ''from itertools import izip_longest; dict(izip_longest(*[iter(range(10000000))]*2, fillvalue=None))''
real 0m2.102s
user 0m1.451s
sys 0m0.539s
Sin embargo, el costo de importar el módulo tiene su costo en conjuntos de datos más pequeños, con un mapa que regresa mucho más rápido hasta alrededor de 100 mil registros cuando comienzan a llegar cara a cara.
$ time python -c ''dict(map(None, *[iter(range(100))]*2))''
real 0m0.046s
user 0m0.029s
sys 0m0.015s
$ time python -c ''from itertools import izip_longest; dict(izip_longest(*[iter(range(100))]*2, fillvalue=None))''
real 0m0.067s
user 0m0.042s
sys 0m0.021s
$ time python -c ''dict(map(None, *[iter(range(100000))]*2))''
real 0m0.074s
user 0m0.050s
sys 0m0.022s
$ time python -c ''from itertools import izip_longest; dict(izip_longest(*[iter(range(100000))]*2, fillvalue=None))''
real 0m0.075s
user 0m0.047s
sys 0m0.024s
¡No le veas nada! =)
nJoy!
Usando la receta de mero habitual, podrías hacer:
Python 2:
d = dict(itertools.izip_longest(*[iter(l)] * 2, fillvalue=""))
Python 3:
d = dict(itertools.zip_longest(*[iter(l)] * 2, fillvalue=""))