¿Cómo convierto dos listas en un diccionario?

Imagina que tienes la siguiente lista.

keys = ['name', 'age', 'food']
values = ['Monty', 42, 'spam']

¿Cuál es la forma más sencilla de producir el siguiente diccionario?

a_dict = {'name': 'Monty', 'age': 42, 'food': 'spam'}

preguntado Oct 16 '08, 17:10

18 Respuestas

Me gusta:

keys = ['a', 'b', 'c']
values = [1, 2, 3]
dictionary = dict(zip(keys, values))
print(dictionary) # {'a': 1, 'b': 2, 'c': 3}

Voila :-) El par dict constructor y zip función son increíblemente útiles.

Respondido 13 Feb 21, 18:02

Vale la pena señalar que dictionary = {zip(keys, values)} no funcionará. Tienes que declarar explícitamente como dict(...) - fernando wittman

No estoy seguro de por qué lo esperarías, @FernandoWittmann. {thing} es azúcar sintáctico para construir un set() que contiene un elemento. {*iterable} es azúcar sintáctico para construir un set que contiene varios elementos. {k:v} or {**mapping} seguirá construir un dict, pero eso es sintácticamente bastante distinto. - Dan Lenski

Gracias por el comentario Dan. Tienes razón. Mi confusión ocurrió porque suelo usar la sintaxis {} para diccionarios. De hecho, si intentamos type({}) la salida es dict. Pero de hecho, si intentamos type({thing}) entonces la salida es set. - fernando wittman

Vine aquí en caso de que podamos hacerlo mejor que {k:v for k, v in zip(keys, values)}. Resulta que podemos. +1. - JG

Gracias, pero no todas las preguntas tienen una respuesta tan rotunda, @Ghost. 😂 - Dan Lenski

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 performante, 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 con mayor rendimiento.

dict(zip(keys, values)) requiere la búsqueda global única para cada uno 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 dict:

Un segundo lugar cercano al uso del constructor dict es usar la sintaxis nativa de una comprensión de dict (no una -- 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 (con un alias para zip puede reducir los cambios de código cuando se cambia 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 <= 2.6

izip desde itertools se convierte en zip en Python 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 utilizar un iterable evitando la creación de 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 comprensión de la lista, se crea innecesariamente una lista adicional. Esperaría que todos ellos tuvieran un rendimiento menor, y ciertamente no más.

Revisión de desempeño:

En Python 64 de 3.8.2 bits proporcionado por Nix, en Ubuntu 16.04, ordenado de más rápido a 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 forma de comparar el rendimiento. Seguramente mean y/o max serían indicadores mucho más útiles para el uso real.

Utilizamos 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 usamos mean, ese tipo de eventos sesgaría mucho nuestros resultados, y si usáramos max Solo obtendremos el resultado más extremo: el que probablemente se vea afectado por tal evento.

Un comentarista también dice:

En Python 3.6.8, usando valores medios, la comprensión de dictados es de hecho aún más rápida, alrededor del 30% para estas pequeñas listas. Para listas más grandes (10k números aleatorios), el dict la llamada es aproximadamente 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 dominen en grandes conjuntos de datos, y no me sorprendería que los bloqueos del sistema operativo dominen dado el tiempo que tomaría ejecutar esa prueba, sesgando aún más sus números. Y si usas mean or max Consideraría que sus resultados no tienen sentido.

Usemos un tamaño más realista en nuestros ejemplos principales:

import numpy
import timeit
l1 = list(numpy.random.random(100))
l2 = list(numpy.random.random(100))

Y vemos aqui 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

Respondido 08 Abr '20, 13:04

A mediados de 2019 (Python 3.7.3), encuentro diferentes tiempos. %% timeit devuelve 1.57 \ pm 0.019microsec para dict(zip(headList, textList)) & 1.95 \ pm 0.030 microsec para {k: v for k, v in zip(headList, textList)}. Sugeriría el primero por su legibilidad y velocidad. Obviamente, esto llega al argumento min () vs mean () para timeit. - marca_anderson

Parece que estás diciendo que la comprensión de dict es más rápida, pero luego, en la revisión de desempeño, dict(zip(keys, values)) mira más rápido. ¿Quizás olvidó actualizar algo? - Loisaida Sam Sandberg

Nota menor (en gran parte irrelevante dada la EOL de Python 2): puede usar from future_builtins import zip como alternativa a from 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 3 zip como reemplazo de regular zip. Es exactamente equivalente a ser claro (future_builtins.zip es en sí mismo solo un alias de itertools.izip). - ShadowRanger

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.

Respondido el 13 de Septiembre de 17 a las 12:09

Verdadero 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 que six usos zip en Python 3 para reemplazar itertools.izip en Python 2 pythonhosted.org/six . - Pedro Cattori

>>> keys = ('name', 'age', 'food')
>>> values = ('Monty', 42, 'spam')
>>> dict(zip(keys, values))
{'food': 'spam', 'age': 42, 'name': 'Monty'}

Respondido 16 Oct 08, 20:10

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'}

Respondido el 10 de junio de 12 a las 21:06

Una forma más natural es utilizar la comprensión del diccionario.

keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')    
dict = {keys[i]: values[i] for i in range(len(keys))}

Respondido 13 Abr '16, 03:04

a veces es la forma más rápida y a veces es más lento convertir a dict objeto, ¿por qué es así ?, gracias amigo. - Haritsinh Gohil

Si necesita transformar claves o valores antes de crear un diccionario, entonces un expresión generadora puede ser usado. Ejemplo:

>>> adict = dict((str(k), v) for k, v in zip(['a', 1, 'b'], [2, 'c', 3])) 

Echa un vistazo Codifique como un Pythonista: Python idiomático.

Respondido 16 Oct 08, 21:10

con Python 3.x, se aplica a las comprensiones de dic

keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')

dic = {k:v for k,v in zip(keys, values)}

print(dic)

Más información sobre Dict comprensiones aquí, un ejemplo está ahí:

>>> print {i : chr(65+i) for i in range(4)}
    {0 : 'A', 1 : 'B', 2 : 'C', 3 : 'D'}

contestado el 25 de mayo de 13 a las 14:05

Para aquellos que necesitan un código simple y no están familiarizados con zip:

List1 = ['This', 'is', 'a', 'list']
List2 = ['Put', 'this', 'into', 'dictionary']

Esto se puede hacer con una línea de código:

d = {List1[n]: List2[n] for n in range(len(List1))}

Respondido 28 Abr '13, 16:04

falla ruidosamente si List1 es más largo que List2 - Jean-François Fabre ♦

@ Jean-FrançoisFabre ¿Realmente importa? ¿Cuál es la razón por la que deberíamos crear dos listas de diferente longitud para construir un diccionario? - amado.por.Jesús

probablemente no, pero después de esto for n in range(len(List1)) es un anti-patrón - Jean-François Fabre ♦

  • 2018-04-18

La mejor solución sigue siendo:

In [92]: keys = ('name', 'age', 'food')
...: values = ('Monty', 42, 'spam')
...: 

In [93]: dt = dict(zip(keys, values))
In [94]: dt
Out[94]: {'age': 42, 'food': 'spam', 'name': 'Monty'}

Transponerlo:

    lst = [('name', 'Monty'), ('age', 42), ('food', 'spam')]
    keys, values = zip(*lst)
    In [101]: keys
    Out[101]: ('name', 'age', 'food')
    In [102]: values
    Out[102]: ('Monty', 42, 'spam')

Respondido 18 Abr '18, 03:04

puede usar este código a continuación:

dict(zip(['name', 'age', 'food'], ['Monty', 42, 'spam']))

Pero asegúrese de que la longitud de las listas sea la misma. Si la longitud no es la misma, entonces la función zip gira la más larga.

respondido 16 nov., 17:13

Aquí también hay un ejemplo de cómo agregar un valor de lista en su diccionario

list1 = ["Name", "Surname", "Age"]
list2 = [["Cyd", "JEDD", "JESS"], ["DEY", "AUDIJE", "PONGARON"], [21, 32, 47]]
dic = dict(zip(list1, list2))
print(dic)

asegúrese siempre de que su "Clave" (lista1) esté siempre en el primer parámetro.

{'Name': ['Cyd', 'JEDD', 'JESS'], 'Surname': ['DEY', 'AUDIJE', 'PONGARON'], 'Age': [21, 32, 47]}

Respondido 20 Feb 19, 12:02

Tuve esta duda mientras intentaba resolver un problema relacionado con un gráfico. El problema que tuve fue que necesitaba definir una lista de adyacencia vacía y quería inicializar todos los nodos con una lista vacía, ahí es cuando pensé, ¿qué tal si verifico si es lo suficientemente rápido, quiero decir si valdrá la pena hacer una operación zip? en lugar de un par clave-valor de asignación simple. Después de todo, la mayoría de las veces, el factor tiempo es un importante rompehielos. Así que realicé la operación timeit para ambos enfoques.

import timeit
def dictionary_creation(n_nodes):
    dummy_dict = dict()
    for node in range(n_nodes):
        dummy_dict[node] = []
    return dummy_dict


def dictionary_creation_1(n_nodes):
    keys = list(range(n_nodes))
    values = [[] for i in range(n_nodes)]
    graph = dict(zip(keys, values))
    return graph


def wrapper(func, *args, **kwargs):
    def wrapped():
        return func(*args, **kwargs)
    return wrapped

iteration = wrapper(dictionary_creation, n_nodes)
shorthand = wrapper(dictionary_creation_1, n_nodes)

for trail in range(1, 8):
    print(f'Itertion: {timeit.timeit(iteration, number=trails)}\nShorthand: {timeit.timeit(shorthand, number=trails)}')

Para n_nodes = 10,000,000 obtengo,

Iteración: 2.825081646999024 Taquigrafía: 3.535717916001886

Iteración: 5.051560923002398 Taquigrafía: 6.255070794999483

Iteración: 6.52859034499852 Taquigrafía: 8.221581164998497

Iteración: 8.683652416999394 Taquigrafía: 12.599181543999293

Iteración: 11.587241565001023 Taquigrafía: 15.27298851100204

Iteración: 14.816342867001367 Taquigrafía: 17.162912737003353

Iteración: 16.645022411001264 Taquigrafía: 19.976680120998935

Puede ver claramente después de cierto punto, el enfoque de iteración en el n_ésimo paso supera el tiempo que toma el enfoque taquigráfico en el n-1_ésimo paso.

Respondido 20 Jul 19, 11:07

Solución como comprensión de diccionario con enumerar:

dict = {item : values[index] for index, item in enumerate(keys)}

Solución como para bucle con enumerar:

dict = {}
for index, item in enumerate(keys):
    dict[item] = values[index]

respondido 05 nov., 19:08

Si está trabajando con más de 1 conjunto de valores y desea tener un lista de dictados puedes usar esto:

def as_dict_list(data: list, columns: list):
    return [dict((zip(columns, row))) for row in data]

El ejemplo de la vida real sería una lista de tuplas de una consulta de base de datos emparejada con una tupla de columnas de la misma consulta. Otras respuestas solo se proporcionaron de 1 a 1.

Respondido el 16 de diciembre de 20 a las 14:12

método sin función zip

l1 = [1,2,3,4,5]
l2 = ['a','b','c','d','e']
d1 = {}
for l1_ in l1:
    for l2_ in l2:
        d1[l1_] = l2_
        l2.remove(l2_)
        break  

print (d1)


{1: 'd', 2: 'b', 3: 'e', 4: 'a', 5: 'c'}

Respondido el 31 de enero de 19 a las 08:01

Hola xiyurui, La entrada (l1 y l2) debería ser una lista. Si asigna l1 y l2 como un conjunto, es posible que no conserve el orden de inserción. para mí obtuve la salida como {1: 'a', 2: 'c', 3: 'd', 4: 'b', 5: 'e'} - Nursnaaz

También puede probar con una lista que es una combinación de dos listas;)

a = [1,2,3,4]
n = [5,6,7,8]

x = []
for i in a,n:
    x.append(i)

print(dict(zip(x[0], x[1])))

Respondido el 02 de junio de 20 a las 11:06

Aunque hay varias formas de hacer esto, creo que es la forma más fundamental de abordarlo; crear un bucle y un diccionario y almacenar valores en ese diccionario. En el enfoque recursivo, la idea sigue siendo la misma, pero en lugar de usar un bucle, la función se llama a sí misma hasta que llega al final. Por supuesto que hay otros enfoques como usar dict(zip(key, value)) y etc. Éstas no son las soluciones más efectivas.

y = [1,2,3,4]
x = ["a","b","c","d"]

# This below is a brute force method
obj = {}
for i in range(len(y)):
    obj[y[i]] = x[i]
print(obj)

# Recursive approach 
obj = {}
def map_two_lists(a,b,j=0):
    if j < len(a):
        obj[b[j]] = a[j]
        j +=1
        map_two_lists(a, b, j)
        return obj
      


res = map_two_lists(x,y)
print(res)

Ambos resultados deberían imprimirse

{1: 'a', 2: 'b', 3: 'c', 4: 'd'}  

Respondido el 03 de Septiembre de 20 a las 05:09

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.