2009-10-12 15 views
6

Sono un nuovo Python e sto cercando di implementare il codice in modo più Pythonico ed efficiente. Dato un dizionario con chiavi e valori numerici, qual è il modo migliore per trovare la chiave più grande con un valore diverso da zero?Modo efficiente per trovare la chiave più grande in un dizionario con valore diverso da zero

Grazie

+0

Forse dovresti utilizzare una struttura dati più appropriata, come un heap, per recuperare valori min/max in una raccolta. – Juliet

+1

"Più Pythonic" di cosa? Qual è la tua attuale soluzione? Cosa non ti piace a riguardo? –

risposta

12

Qualcosa del genere dovrebbe essere ragionevolmente veloce:

>>> x = {0: 5, 1: 7, 2: 0} 
>>> max(k for k, v in x.iteritems() if v != 0) 
1 

(. Rimuovendo il != 0 sarà leggermente più veloce ancora, ma oscura il senso un po ') la funzione max

+2

Poiché l'OP è nuovo, può essere utile anche una descrizione di ciò che sta accadendo. –

+6

Si noti che in Python 3.x '.iteritems' non esiste più e' .items' restituisce un iteratore. (A differenza di Python 2.x, dove '.items' restituisce una lista e' .iteritems' restituisce un iteratore.) – Stephan202

+3

Cosa sta succedendo qui? Stiamo chiamando max() per trovare la chiave più grande. Quello che passiamo a max() è una "espressione generatore", molto simile a una "lista di comprensione". max() otterrà ripetutamente i valori per k e selezionerà il più grande. L'espressione del generatore restituirà solo k valori quando il valore v non è zero. I valori k e v provengono da x.iteritems(), che restituisce coppie chiave, valore. Questo codice funzionerà in Python 2.4 e successivi, ma come notato da Stephan202, per Python 3.x è necessario sostituire "iteritems" con solo "elementi". – steveha

1

di Python prende un Parametro key= per una funzione di "misura".

data = {1: 25, 0: 75} 
def keymeasure(key): 
    return data[key] and key 

print max(data, key=keymeasure) 

L'utilizzo di un lambda in linea nello stesso senso e la stessa vincolante delle variabili locali:

print max(data, key=(lambda k: data[k] and k)) 

ultima alternativa per legare nel var locale nella funzione di chiave anonima

print max(data, key=(lambda k, mapping=data: mapping[k] and k)) 
+1

Questa funzione dipende dall'accesso al globale.Cattiva idea. –

+1

No, non è così. Ciò dipende solo dall'avere accesso allo stesso ambito. Tutto ciò può essere all'interno di un ambito di funzione e funzionerebbe ancora. –

+2

@dalke, il punto rimane che la funzione dovrebbe prendere il dizionario come argomento, piuttosto che codificare il nome del dict. – steveha

10

Per ottenere la chiave più grande, è possibile utilizzare la funzione max e ispezionare le chiavi in ​​questo modo:

max(x.iterkeys()) 

per filtrare quelli in cui il valore è 0, è possibile utilizzare un generator expression:

(k for k, v in x.iteritems() if v != 0) 

È possibile combinare questi per ottenere ciò che si sta cercando (dal max richiede un solo argomento, le parentesi intorno l'espressione generatore può essere eliminato):

max(k for k, v in x.iteritems() if v != 0) 
+2

Quasi lì! Infine, rimuovi le parentesi quadre e ti rimane la soluzione migliore. Le parentesi quadre formano una lista di comprensione, che costruisce l'intera lista, e quindi l'intera lista viene passata a max(). Tralasciando le parentesi quadre, si ottiene un'espressione generatore, che trasferisce i valori uno alla volta a max(). Per un numero limitato di elementi non è un grosso problema, ma per dizionari molto grandi, lo sforzo extra per creare un elenco e quindi distruggerlo può essere considerevole. – steveha

+0

Ho appena aggiornato la mia risposta ... passato da elenchi a generatori/iteratori –

+2

Solo per vostra informazione, non avete bisogno degli extra parens. I parens di max() possono fare il doppio lavoro: possono essere i paren per la funzione call a max() e possono anche essere i parens attorno all'espressione del generatore. Provalo! :-) – steveha

0

Se fossi in te e la velocità era una grande preoccupazione, probabilmente sarei creare una nuova classe contenitore "DictMax" che sarebbe tenere traccia del suo più grande valore diverso da zero elementi avendo una pila interna di ind exes, dove l'elemento principale dello stack è sempre la chiave dell'elemento più grande nel dizionario. In questo modo otterrai sempre l'elemento più grande in tempo costante.

Problemi correlati