Guido
Quiero combinar estos:
keys = ['name', 'age', 'food']
values = ['Monty', 42, 'spam']
En un solo diccionario:
{'name': 'Monty', 'age': 42, 'food': 'spam'}
Dan Lenski
Como esto:
keys = ['a', 'b', 'c']
values = [1, 2, 3]
dictionary = dict(zip(keys, values))
print(dictionary) # {'a': 1, 'b': 2, 'c': 3}
Voila 🙂 Los pares dict
constructor y zip
función son increíblemente útiles.
-
Cabe resaltar que
dictionary = {zip(keys, values)}
no funcionará Tienes que declarar explícitamente comodict(...)
– Fernando Witmann
28 de agosto de 2019 a las 15:52
-
No estoy seguro de por qué esperarías que lo hiciera, @FernandoWittmann.
{thing}
es azúcar sintáctico para construir unset()
que contiene un elemento.{*iterable}
es azúcar sintáctico para construir unset
que contiene varios elementos.{k:v}
o{**mapping}
voluntad construir undict
pero eso es sintácticamente bastante distinto.– Dan Lensky
28 de agosto de 2019 a las 16:41
-
Gracias por el comentario Dan. Tienes razón. Mi confusión ocurrió porque suelo usar la sintaxis
{}
para diccionarios. De hecho, si intentamostype({})
la salida esdict
. Pero de hecho, si intentamostype({thing})
entonces la salida esset
.– Fernando Witmann
28 de agosto de 2019 a las 17:42
-
Vine aquí en caso de que podamos hacerlo mejor que
{k:v for k, v in zip(keys, values)}
. Resulta que podemos. +1.– JG
23 de enero de 2020 a las 14:28
-
@FernandoWittmann tienes razón en que es confuso.
{[thing1, thing2, … thingN]}
crea un conjunto para cualquier valor deN != 0
; pero paraN == 0
crea un vacíodict
y tienes que hacerset()
para crear un conjunto vacío. Es un poco desafortunado, y PoLS-violación, verruga de Python, debido al hecho de que Python teníadict
-literales mucho antesset
-literales.– Dan Lensky
29 de octubre de 2020 a las 0:14
Rusia debe sacar a Putin
Imagina que tienes:
keys = ('name', 'age', 'food') values = ('Monty', 42, 'spam')
¿Cuál es la forma más sencilla de producir el siguiente diccionario?
dict = {'name' : 'Monty', 'age' : 42, 'food' : 'spam'}
más eficaz, dict
constructor con zip
new_dict = dict(zip(keys, values))
En Python 3, zip ahora devuelve un iterador perezoso, y este es ahora el enfoque de mayor rendimiento.
dict(zip(keys, values))
requiere la búsqueda global única para cada dict
y zip
pero no forma estructuras de datos intermedias innecesarias ni tiene que lidiar con búsquedas locales en la aplicación de funciones.
Subcampeón, comprensión de dictados:
Un finalista cercano al uso del constructor dict es usar la sintaxis nativa de una comprensión dict (no un lista comprensión, como otros han dicho erróneamente):
new_dict = {k: v for k, v in zip(keys, values)}
Elija esto cuando necesite mapear o filtrar según las claves o el valor.
En Python 2, zip
devuelve una lista, para evitar crear una lista innecesaria, utilice izip
en su lugar (el alias de zip puede reducir los cambios de código cuando pasa a Python 3).
from itertools import izip as zip
Entonces eso sigue siendo (2.7):
new_dict = {k: v for k, v in zip(keys, values)}
Python 2, ideal para
izip
de itertools
se convierte zip
en Phyton 3. izip
es mejor que zip para Python 2 (porque evita la creación de listas innecesarias) e ideal para 2.6 o inferior:
from itertools import izip
new_dict = dict(izip(keys, values))
Resultado para todos los casos:
En todos los casos:
>>> new_dict
{'age': 42, 'name': 'Monty', 'food': 'spam'}
Explicación:
Si miramos la ayuda en dict
vemos que toma una variedad de formas de argumentos:
>>> help(dict)
class dict(object)
| dict() -> new empty dictionary
| dict(mapping) -> new dictionary initialized from a mapping object's
| (key, value) pairs
| dict(iterable) -> new dictionary initialized as if via:
| d = {}
| for k, v in iterable:
| d[k] = v
| dict(**kwargs) -> new dictionary initialized with the name=value pairs
| in the keyword argument list. For example: dict(one=1, two=2)
El enfoque óptimo es usar un iterable y evitar crear estructuras de datos innecesarias. En Python 2, zip crea una lista innecesaria:
>>> zip(keys, values)
[('name', 'Monty'), ('age', 42), ('food', 'spam')]
En Python 3, el equivalente sería:
>>> list(zip(keys, values))
[('name', 'Monty'), ('age', 42), ('food', 'spam')]
y Python 3 zip
simplemente crea un objeto iterable:
>>> zip(keys, values)
<zip object at 0x7f0e2ad029c8>
Dado que queremos evitar la creación de estructuras de datos innecesarias, generalmente queremos evitar Python 2 zip
(ya que crea una lista innecesaria).
Alternativas de menor rendimiento:
Esta es una expresión generadora que se pasa al constructor dict:
generator_expression = ((k, v) for k, v in zip(keys, values))
dict(generator_expression)
o equivalente:
dict((k, v) for k, v in zip(keys, values))
Y esta es una lista de comprensión que se pasa al constructor dict:
dict([(k, v) for k, v in zip(keys, values)])
En los dos primeros casos, se coloca una capa adicional de cálculo no operativo (por lo tanto, innecesario) sobre el zip iterable, y en el caso de la lista por comprensión, se crea innecesariamente una lista adicional. Esperaría que todos ellos tuvieran menos rendimiento, y ciertamente no más.
Revisión de desempeño:
En Python 3.8.2 de 64 bits proporcionado por Nix, en Ubuntu 16.04, ordenado del más rápido al más lento:
>>> min(timeit.repeat(lambda: dict(zip(keys, values))))
0.6695233230129816
>>> min(timeit.repeat(lambda: {k: v for k, v in zip(keys, values)}))
0.6941362579818815
>>> min(timeit.repeat(lambda: {keys[i]: values[i] for i in range(len(keys))}))
0.8782548159942962
>>>
>>> min(timeit.repeat(lambda: dict([(k, v) for k, v in zip(keys, values)])))
1.077607496001292
>>> min(timeit.repeat(lambda: dict((k, v) for k, v in zip(keys, values))))
1.1840861019445583
dict(zip(keys, values))
gana incluso con pequeños conjuntos de claves y valores, pero para conjuntos más grandes, las diferencias en el rendimiento serán mayores.
Un comentarista dijo:
min
parece una mala manera de comparar el rendimiento. Seguramentemean
y/omax
serían indicadores mucho más útiles para el uso real.
Usamos min
porque estos algoritmos son deterministas. Queremos conocer el rendimiento de los algoritmos en las mejores condiciones posibles.
Si el sistema operativo se bloquea por algún motivo, no tiene nada que ver con lo que estamos tratando de comparar, por lo que debemos excluir ese tipo de resultados de nuestro análisis.
si usáramos mean
ese tipo de eventos sesgarían mucho nuestros resultados, y si usáramos max
solo obtendremos el resultado más extremo, el más probablemente afectado por tal evento.
Un comentarista también dice:
En python 3.6.8, usando valores medios, la comprensión de dict es aún más rápida, aproximadamente un 30 % para estas listas pequeñas. Para listas más grandes (10k números aleatorios), el
dict
la llamada es un 10% más rápida.
Supongo que queremos decir dict(zip(...
con 10k números aleatorios. Eso suena como un caso de uso bastante inusual. Tiene sentido que las llamadas más directas predominen en grandes conjuntos de datos, y no me sorprendería que los bloqueos del sistema operativo dominen dado el tiempo que llevaría ejecutar esa prueba, sesgando aún más sus números. Y si usas mean
o max
Consideraría que sus resultados no tienen sentido.
Usemos un tamaño más realista en nuestros mejores ejemplos:
import numpy
import timeit
l1 = list(numpy.random.random(100))
l2 = list(numpy.random.random(100))
Y vemos aquí que dict(zip(...
de hecho, se ejecuta más rápido para conjuntos de datos más grandes en aproximadamente un 20%.
>>> min(timeit.repeat(lambda: {k: v for k, v in zip(l1, l2)}))
9.698965263989521
>>> min(timeit.repeat(lambda: dict(zip(l1, l2))))
7.9965161079890095
-
A mediados de 2019 (python 3.7.3), encuentro diferentes tiempos. %%timeit devuelve 1,57 \pm 0,019 microsegundos para
dict(zip(headList, textList))
& 1.95 \pm 0.030 microsegundos para{k: v for k, v in zip(headList, textList)}
. Sugeriría el primero por legibilidad y velocidad. Obviamente, esto llega al argumento min() vs mean() para timeit.– Mark_Anderson
2 de julio de 2019 a las 15:06
-
Parece que estás diciendo que la comprensión de dict es más rápida, pero luego en la revisión de rendimiento,
dict(zip(keys, values))
se ve más rápido. ¿Quizás olvidaste actualizar algo?– Loisaida Sam Sandberg
8 de abril de 2020 a las 2:57
-
Nota menor (en gran parte irrelevante dada la EOL de Python 2): puede usar
from future_builtins import zip
como alternativa afrom itertools import izip as zip
eso es un poco más explícito sobre la descripción de la importación en términos de obtener Python 3zip
como reemplazo de los regulareszip
. Es exactamente equivalente a ser claro (future_builtins.zip
es en sí mismo sólo un alias deitertools.izip
).– ShadowRanger
29 de octubre de 2020 a las 18:24
mike davis
Prueba esto:
>>> import itertools
>>> keys = ('name', 'age', 'food')
>>> values = ('Monty', 42, 'spam')
>>> adict = dict(itertools.izip(keys,values))
>>> adict
{'food': 'spam', 'age': 42, 'name': 'Monty'}
En Python 2, también es más económico en el consumo de memoria en comparación con zip
.
-
Cierto para Python2, pero en Python 3,
zip
ya es económico en el consumo de memoria. docs.python.org/3/library/functions.html#zip De hecho, puedes ver quesix
usoszip
en Python 3 para reemplazaritertools.izip
en pitón 2 pythonhosted.org/six .– Pedro Cattori
17 de febrero de 2017 a las 14:56
-
respuesta obsoleta
– Julio GM
24 ago a las 20:01
eny
keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')
out = dict(zip(keys, values))
Producción:
{'food': 'spam', 'age': 42, 'name': 'Monty'}
También puede usar comprensiones de diccionario en Python ≥ 2.7:
>>> keys = ('name', 'age', 'food')
>>> values = ('Monty', 42, 'spam')
>>> {k: v for k, v in zip(keys, values)}
{'food': 'spam', 'age': 42, 'name': 'Monty'}
Una forma más natural es usar la comprensión del diccionario.
keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')
dict = {keys[i]: values[i] for i in range(len(keys))}
jfs
Si necesita transformar claves o valores antes de crear un diccionario, entonces un generador de expresión puede ser usado. Ejemplo:
>>> adict = dict((str(k), v) for k, v in zip(['a', 1, 'b'], [2, 'c', 3]))
Echar un vistazo Codifique como un Pythonista: Python idiomático.
Mira mi respuesta @ stackoverflow.com/a/73768661/9384511
– ABN
19 de septiembre a las 4:58