Respuestas:
Me gusta esto:
>>> keys = ['a', 'b', 'c']
>>> values = [1, 2, 3]
>>> dictionary = dict(zip(keys, values))
>>> print(dictionary)
{'a': 1, 'b': 2, 'c': 3}
Voila :-) El dict
constructor por pares y la zip
función son increíblemente útiles: https://docs.python.org/3/library/functions.html#func-dict
{thing}
es azúcar sintáctico para construir un set()
elemento que contiene un elemento. {*iterable}
Es un azúcar sintáctico para construir un que set
contiene varios elementos. {k:v}
o {**mapping}
va a construir una dict
, pero eso es sintácticamente muy distinta.
{}
para los diccionarios. De hecho, si intentamos type({})
la salida es dict
. Pero, de hecho, si lo intentamos, type({thing})
entonces la salida es set
.
{k:v for k, v in zip(keys, values)}
. Resulta que podemos. +1.
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'}
dict
Constructor con más rendimientozip
new_dict = dict(zip(keys, values))
En Python 3, zip ahora devuelve un iterador perezoso, y este es ahora el enfoque más eficaz.
dict(zip(keys, values))
requiere la búsqueda global de una sola vez para 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.
Un finalista cercano al uso del constructor dict es usar la sintaxis nativa de una comprensión dict (no una comprensión de lista , como otros lo han expresado erróneamente):
new_dict = {k: v for k, v in zip(keys, values)}
Elija esto cuando necesite asignar o filtrar según las claves o el valor.
En Python 2, zip
devuelve una lista, para evitar crear una lista innecesaria, use izip
en su lugar (alias a zip puede reducir los cambios de código cuando se mueve 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)}
izip
from se itertools
convierte zip
en Python 3. izip
es mejor que zip para Python 2 (porque evita la creación innecesaria de listas), e ideal para 2.6 o menos:
from itertools import izip
new_dict = dict(izip(keys, values))
En todos los casos:
>>> new_dict
{'age': 42, 'name': 'Monty', 'food': 'spam'}
Si miramos la ayuda 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 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>
Como queremos evitar crear estructuras de datos innecesarias, generalmente queremos evitar Python 2 zip
(ya que crea una lista innecesaria).
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 primeros dos casos, se coloca una capa adicional de cómputo 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 sean menos eficientes, y ciertamente no más.
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 lo usáramos mean
, ese tipo de eventos sesgaría nuestros resultados en gran medida, y si lo max
usáramos 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 de hecho aún más rápida, en aproximadamente un 30% para estas pequeñas listas. Para listas más grandes (10k números aleatorios), la
dict
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 si los bloqueos del sistema operativo son dominantes dado el tiempo que tomaría ejecutar esa prueba, sesgando aún más sus números. Y si usa mean
o max
consideraría sus resultados sin 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 aquí que de dict(zip(...
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
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 legibilidad y velocidad. Obviamente, esto llega al argumento min () vs mean () para timeit.
min
Parece una mala manera de comparar el rendimiento. Seguramente mean
y / o max
serían indicadores mucho más útiles para el uso real.
dict
llamada es aproximadamente un 10% más rápida.
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 consumo de memoria en comparación con zip
.
zip
ya es económico en consumo de memoria. docs.python.org/3/library/functions.html#zip De hecho, puede ver que six
utiliza zip
Python 3 para reemplazar itertools.izip
Python 2 pythonhosted.org/six .
También puede usar las 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 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))}
dict
objeto, ¿por qué es así ?, gracias amigo.
Si necesita transformar claves o valores antes de crear un diccionario, se podría usar una expresión generadora . Ejemplo:
>>> adict = dict((str(k), v) for k, v in zip(['a', 1, 'b'], [2, 'c', 3]))
Eche un vistazo Código como un Pythonista: Idiomatic Python .
con Python 3.x, va para comprensiones dict
keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')
dic = {k:v for k,v in zip(keys, values)}
print(dic)
Más sobre las comprensiones dict aquí , un ejemplo está allí:
>>> print {i : chr(65+i) for i in range(4)}
{0 : 'A', 1 : 'B', 2 : 'C', 3 : 'D'}
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))}
List1
es más largo queList2
for n in range(len(List1))
es un antipatrón
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'}
Tranponerlo:
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')
puedes 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. Luego la función zip gira la más larga.
Tuve esta duda mientras intentaba resolver un problema relacionado con el 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, fue entonces cuando pensé en comprobar si era lo suficientemente rápido, es decir, si valdría la pena hacer una operación zip en lugar de simple par clave-valor de asignación. Después de la mayoría de las veces, el factor tiempo es un rompehielos importante. 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 Abreviatura: 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
Después de cierto punto, puede ver claramente que el enfoque de iteración en el n-ésimo paso supera el tiempo empleado por el método abreviado en el n-1 ° paso.
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)
siempre asegúrese de que su "Clave" (lista1) esté siempre en el primer parámetro.
{'Name': ['Cyd', 'JEDD', 'JESS'], 'Surname': ['DEY', 'AUDIJE', 'PONGARON'], 'Age': [21, 32, 47]}
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])))
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'}
dictionary = {zip(keys, values)}
eso no funcionará. Tienes que declarar explícitamente comodict(...)