Risposte:
Come questo:
>>> keys = ['a', 'b', 'c']
>>> values = [1, 2, 3]
>>> dictionary = dict(zip(keys, values))
>>> print(dictionary)
{'a': 1, 'b': 2, 'c': 3}
Voila :-) Il dict
costruttore e la zip
funzione a coppie sono incredibilmente utili: https://docs.python.org/3/library/functions.html#func-dict
{thing}
è zucchero sintattico per costruire un set()
contenente un elemento. {*iterable}
è zucchero sintattico per costruire un set
contenente più elementi. {k:v}
o {**mapping}
sarà costruire una dict
, ma è sintatticamente ben distinti.
{}
per i dizionari. In effetti, se proviamo type({})
l'output è dict
. Ma in effetti, se ci proviamo, type({thing})
l'output è set
.
{k:v for k, v in zip(keys, values)}
. Si scopre che possiamo. +1.
Immagina di avere:
keys = ('name', 'age', 'food') values = ('Monty', 42, 'spam')
Qual è il modo più semplice per produrre il seguente dizionario?
dict = {'name' : 'Monty', 'age' : 42, 'food' : 'spam'}
dict
costruttore conzip
new_dict = dict(zip(keys, values))
In Python 3, zip ora restituisce un iteratore pigro, e questo è ora l'approccio più performante.
dict(zip(keys, values))
richiede la ricerca globale una tantum per ciascuna dict
e zip
, ma non costituisce alcuna struttura di dati intermedia non necessaria né deve occuparsi di ricerche locali nell'applicazione delle funzioni.
Un secondo passo per usare il costruttore dict è usare la sintassi nativa di una comprensione dict (non una comprensione dell'elenco , come altri l'hanno erroneamente definita):
new_dict = {k: v for k, v in zip(keys, values)}
Scegli questo quando è necessario mappare o filtrare in base alle chiavi o al valore.
In Python 2, zip
restituisce un elenco, per evitare di creare un elenco non necessario, utilizzare izip
invece (aliasato per zip può ridurre le modifiche al codice quando si passa a Python 3).
from itertools import izip as zip
Quindi è ancora (2.7):
new_dict = {k: v for k, v in zip(keys, values)}
izip
from itertools
diventa zip
in Python 3. izip
è meglio di zip per Python 2 (perché evita la creazione di elenchi superflui) e ideale per 2.6 o precedenti:
from itertools import izip
new_dict = dict(izip(keys, values))
In tutti i casi:
>>> new_dict
{'age': 42, 'name': 'Monty', 'food': 'spam'}
Se guardiamo l'aiuto su dict
vediamo che ci vogliono una varietà di forme di argomenti:
>>> 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)
L'approccio ottimale è utilizzare un iterabile evitando di creare strutture di dati non necessarie. In Python 2, zip crea un elenco non necessario:
>>> zip(keys, values)
[('name', 'Monty'), ('age', 42), ('food', 'spam')]
In Python 3, l'equivalente sarebbe:
>>> list(zip(keys, values))
[('name', 'Monty'), ('age', 42), ('food', 'spam')]
e Python 3 zip
crea semplicemente un oggetto iterabile:
>>> zip(keys, values)
<zip object at 0x7f0e2ad029c8>
Poiché vogliamo evitare di creare strutture di dati non necessarie, di solito vogliamo evitare Python 2 zip
(poiché crea un elenco non necessario).
Questa è un'espressione del generatore che viene passata al costruttore dict:
generator_expression = ((k, v) for k, v in zip(keys, values))
dict(generator_expression)
o equivalentemente:
dict((k, v) for k, v in zip(keys, values))
E questa è una comprensione dell'elenco che viene passata al costruttore del dict:
dict([(k, v) for k, v in zip(keys, values)])
Nei primi due casi, un ulteriore livello di calcolo non operativo (quindi non necessario) viene posizionato sopra lo zip iterabile e, nel caso della comprensione dell'elenco, viene creato inutilmente un elenco aggiuntivo. Mi aspetterei che fossero tutti meno performanti, e certamente non di più.
In 64 bit Python 3.8.2 fornito da Nix, su Ubuntu 16.04, ordinato dal più veloce al più 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))
vince anche con piccoli set di chiavi e valori, ma per set più grandi, le differenze nelle prestazioni diventeranno maggiori.
Un commentatore ha detto:
min
sembra un brutto modo per confrontare le prestazioni. Sicuramentemean
e / omax
sarebbero indicatori molto più utili per un utilizzo reale.
Usiamo min
perché questi algoritmi sono deterministici. Vogliamo conoscere le prestazioni degli algoritmi nelle migliori condizioni possibili.
Se il sistema operativo si blocca per qualsiasi motivo, non ha nulla a che fare con ciò che stiamo cercando di confrontare, quindi dobbiamo escludere questo tipo di risultati dalla nostra analisi.
Se lo usassimo mean
, questo tipo di eventi distorcerebbe notevolmente i nostri risultati, e se lo usassimo max
otterremo solo il risultato più estremo - quello che più probabilmente risentirà di un tale evento.
Un commentatore dice anche:
In python 3.6.8, usando i valori medi, la comprensione del dict è davvero ancora più veloce, di circa il 30% per questi piccoli elenchi. Per elenchi più grandi (10k numeri casuali), la
dict
chiamata è circa il 10% più veloce.
Presumo che intendiamo dict(zip(...
con 10k numeri casuali. Sembra un caso d'uso piuttosto insolito. Ha senso che le chiamate più dirette dominino in set di dati di grandi dimensioni, e non sarei sorpreso se gli hang del sistema operativo stanno dominando dato il tempo necessario per eseguire quel test, distorcendo ulteriormente i numeri. E se usi mean
o max
considererei i tuoi risultati insignificanti.
Usiamo una dimensione più realistica nei nostri migliori esempi:
import numpy
import timeit
l1 = list(numpy.random.random(100))
l2 = list(numpy.random.random(100))
E vediamo qui che dict(zip(...
effettivamente funziona più velocemente per set di dati più grandi di circa il 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 per {k: v for k, v in zip(headList, textList)}
. Vorrei suggerire il primo per leggibilità e velocità. Ovviamente questo arriva all'argomento min () vs mean () per timeit.
min
sembra un brutto modo per confrontare le prestazioni. Sicuramente mean
e / o max
sarebbero indicatori molto più utili per un utilizzo reale.
dict
chiamata è circa il 10% più veloce.
Prova questo:
>>> import itertools
>>> keys = ('name', 'age', 'food')
>>> values = ('Monty', 42, 'spam')
>>> adict = dict(itertools.izip(keys,values))
>>> adict
{'food': 'spam', 'age': 42, 'name': 'Monty'}
In Python 2, è anche più economico nel consumo di memoria rispetto a zip
.
zip
è già economico nel consumo di memoria. docs.python.org/3/library/functions.html#zip In effetti, puoi vedere che six
utilizza zip
in Python 3 per sostituire itertools.izip
in Python 2 pythonhosted.org/six .
Puoi anche usare la comprensione del dizionario in 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'}
Un modo più naturale è usare la comprensione del dizionario
keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')
dict = {keys[i]: values[i] for i in range(len(keys))}
dict
oggetto, perché è così? Grazie amico.
Se è necessario trasformare chiavi o valori prima di creare un dizionario, è possibile utilizzare un'espressione del generatore . Esempio:
>>> adict = dict((str(k), v) for k, v in zip(['a', 1, 'b'], [2, 'c', 3]))
Dai un'occhiata a Code Like a Pythonista: Idiomatic Python .
con Python 3.x, vale per la comprensione del dict
keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')
dic = {k:v for k,v in zip(keys, values)}
print(dic)
Maggiori informazioni sulla comprensione dei dettami qui , c'è un esempio:
>>> print {i : chr(65+i) for i in range(4)}
{0 : 'A', 1 : 'B', 2 : 'C', 3 : 'D'}
Per coloro che hanno bisogno di un codice semplice e non hanno familiarità con zip
:
List1 = ['This', 'is', 'a', 'list']
List2 = ['Put', 'this', 'into', 'dictionary']
Questo può essere fatto con una riga di codice:
d = {List1[n]: List2[n] for n in range(len(List1))}
List1
è più lungo diList2
for n in range(len(List1))
è un anti-pattern
La soluzione migliore è ancora:
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'}
Traslocare:
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')
puoi usare questo codice qui sotto:
dict(zip(['name', 'age', 'food'], ['Monty', 42, 'spam']))
Ma assicurati che la lunghezza degli elenchi sia la stessa. Se la lunghezza non è la stessa, allora la funzione zip trasforma quella più lunga.
Ho avuto questo dubbio mentre cercavo di risolvere un problema legato al grafico. Il problema che avevo era che dovevo definire un elenco di adiacenza vuoto e volevo inizializzare tutti i nodi con un elenco vuoto, fu allora che pensai a come controllare se è abbastanza veloce, intendo se varrà la pena fare un'operazione zip anziché una semplice coppia chiave-valore di assegnazione. Dopo tutto il più delle volte, il fattore tempo è un importante rompighiaccio. Quindi ho eseguito un'operazione timeit per entrambi gli approcci.
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)}')
Per n_nodes = 10.000.000 che ottengo,
Iterazione: 2.825081646999024 Stenografia: 3.535717916001886
Iterazione: 5.051560923002398 Stenografia: 6.255070794999483
Iterazione: 6.52859034499852 Stenografia: 8.221581164998497
Iterazione: 8.683652416999394 Stenografia: 12.599181543999293
Iterazione: 11.587241565001023 Stenografia: 15.27298851100204
Iterazione: 14.816342867001367 Stenografia: 17.162912737003353
Iterazione: 16.645022411001264 Stenografia: 19.976680120998935
È possibile vedere chiaramente dopo un certo punto che l'approccio di iterazione all'n-step supera il tempo impiegato dall'approccio di stenografia all'n-1-step.
Ecco anche un esempio di aggiunta di un valore di elenco nel dizionario
list1 = ["Name", "Surname", "Age"]
list2 = [["Cyd", "JEDD", "JESS"], ["DEY", "AUDIJE", "PONGARON"], [21, 32, 47]]
dic = dict(zip(list1, list2))
print(dic)
assicurati sempre che la tua "Chiave" (list1) sia sempre nel primo parametro.
{'Name': ['Cyd', 'JEDD', 'JESS'], 'Surname': ['DEY', 'AUDIJE', 'PONGARON'], 'Age': [21, 32, 47]}
Puoi anche provare con un elenco che è una combinazione di due elenchi;)
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])))
metodo senza funzione 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)}
non funzionerà. Devi dichiarare esplicitamente comedict(...)