2009-03-17 9 views
10

In primo luogo, sono nuovo di Python, quindi mi scuso se ho trascurato qualcosa, ma mi piacerebbe usare dict.fromkeys (o qualcosa di simile) per creare un dizionario di liste, le cui chiavi sono fornite in un altro elenco. Sto eseguendo alcuni test di temporizzazione e mi piacerebbe per la chiave per essere la variabile di ingresso e la lista per contenere i tempi per le corse:Come posso creare un valore univoco per ogni chiave usando dict.fromkeys?

def benchmark(input): 
    ... 
    return time_taken 

runs = 10 
inputs = (1, 2, 3, 5, 8, 13, 21, 34, 55) 
results = dict.fromkeys(inputs, []) 

for run in range(0, runs): 
    for i in inputs: 
     results[i].append(benchmark(i)) 

Il problema che sto avendo è che tutte le chiavi sembra che il dizionario condivida la stessa lista, e ogni esecuzione viene semplicemente accodata ad essa. C'è un modo per generare una lista vuota unica per ogni chiave usando fromkeys? In caso contrario, c'è un altro modo per farlo senza generare il dizionario risultante a mano?

risposta

10

Il problema è che in

results = dict.fromkeys(inputs, []) 

[] viene valutata solo una volta, proprio lì.

Mi piacerebbe riscrivere il codice così:

runs = 10 
inputs = (1, 2, 3, 5, 8, 13, 21, 34, 55) 
results = {} 

for run in range(runs): 
    for i in inputs: 
     results.setdefault(i,[]).append(benchmark(i)) 

Altra opzione è:

runs = 10 
inputs = (1, 2, 3, 5, 8, 13, 21, 34, 55) 
results = dict([(i,[]) for i in inputs]) 

for run in range(runs): 
    for i in inputs: 
     results[i].append(benchmark(i)) 
+0

Fantastico, funziona benissimo! Grazie! (anche se mi piacerebbe che fosse possibile generare le liste vuote prima che dovessi usarle) –

+0

Non è possibile. Una volta che chiami [] o list() viene creato un oggetto e vincolato a una variabile. Controlla ad esempio questo x = [[]] * 10; x [0] .Append ('test'); print x – vartec

+0

Ok, ci sono alternative con tutte le liste istanziate. – vartec

12

Verificare defaultdict (richiede Python 2.5 o versione successiva).

from collections import defaultdict 

def benchmark(input): 
    ... 
    return time_taken 

runs = 10 
inputs = (1, 2, 3, 5, 8, 13, 21, 34, 55) 
results = defaultdict(list) # Creates a dict where the default value for any key is an empty list 

for run in range(0, runs): 
    for i in inputs: 
     results[i].append(benchmark(i)) 
+0

Anche questo funziona bene - Vorrei solo che fosse un dizionario "reale", non una classe che finge di esserlo. –

+0

Per essere onesti, è una sottoclasse con cambiamenti minimi, quindi "fingere di essere uno" sembra un po 'forte. –

+0

+1 È il modo per farlo se sei sicuro di non dover usare il tuo codice con Python <2.5. (Di recente ho cercato offerte di hosting e molto ancora utilizzano Python 2.4). – vartec

2

Si può anche fare questo se non si vuole imparare qualcosa di nuovo (anche se vi consiglio lo fai!) Sono curioso di sapere quale metodo è più veloce?

results = dict.fromkeys(inputs) 

for run in range(0, runs): 
    for i in inputs: 
     if not results[i]: 
      results[i] = [] 
     results[i].append(benchmark(i)) 
Problemi correlati