2009-10-12 14 views
6

Jestem nowym Pythonem i próbuję zaimplementować kod w bardziej sprytny i wydajny sposób. Biorąc pod uwagę słownik z klawiszami numerycznymi i wartościami, jaki jest najlepszy sposób na znalezienie największego klucza o niezerowej wartości?Skuteczny sposób na znalezienie największego klucza w słowniku o niezerowej wartości

Dzięki

+0

Może powinieneś użyć bardziej odpowiedniej struktury danych, takiej jak sterty, do pobrania wartości min/maks w kolekcji. – Juliet

+1

"Więcej python" niż czym? Jakie jest twoje obecne rozwiązanie? Co ci się nie podoba w tym stylu? –

Odpowiedz

12

Coś jak to powinno być w miarę szybko:

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

(. Usunięcie != 0 będzie nieco szybciej jeszcze, ale zaciemnia sens nieco) max funkcja

+2

Ponieważ OP jest nowy, pomocny może być również opis tego, co się dzieje. –

+6

Zauważ, że w Pythonie 3.x '.iteritems' już nie istnieje, a' .items' zwraca iterator. (W przeciwieństwie do Python 2.x, gdzie '.items' zwraca listę, a' .iteritems' zwraca iterator.) – Stephan202

+3

Co się tutaj dzieje? Wzywamy max(), aby znaleźć największy klucz. To, co przekazujemy do max(), jest "wyrażeniem generującym", bardzo podobnym do "zrozumienia list". max() będzie wielokrotnie uzyskiwał wartości dla k, a wybierze największą. Wyrażenie generatora zwróci wartości k tylko wtedy, gdy wartość v nie będzie równa zero. Wartości k i v pochodzą z x.iteritems(), które zwraca pary kluczy, wartości. Ten kod będzie działał w Pythonie 2.4 i nowszych, ale jak zauważył Stephan202, w Pythonie 3.x musisz zastąpić "iteritems" tylko "elementami". – steveha

1

Pythona trwa key= parametr funkcji "miara".

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

print max(data, key=keymeasure) 

Używanie lambda inline do tego samego efektu i same wiązania zmiennych lokalnych:

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

ostatnia alternatywa wiążą w lokalnej var do funkcji klucza anonimowego

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

Ta funkcja zależy od dostępu do globalnej.Kiepski pomysł. –

+1

Nie, nie ma. To zależy tylko od dostępu do tego samego zakresu. Wszystko to może znajdować się wewnątrz zakresu funkcji i nadal będzie działać. –

+2

@dalke, pozostaje faktem, że funkcja powinna przyjmować słownik jako argument, a nie kodować na sztywno nazwy dyktatora. – steveha

10

Aby zdobądź największy klucz, możesz użyć funkcji max i sprawdzić klucze:

max(x.iterkeys()) 

Aby odfiltrować te, w których wartość wynosi 0, można użyć generator expression:

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

Można łączyć je, aby uzyskać to, czego szukasz (od max trwa tylko jeden argument, nawiasów wokół wyrażenie generator może zostać pominięte):

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

Prawie tam! Na koniec usuwasz nawiasy klamrowe i pozostawiasz najlepsze rozwiązanie. Kwadratowe nawiasy tworzą listę, która buduje całą listę, a następnie cała lista jest przekazywana do max(). Pozostawiając nawiasy klamrowe, uzyskuje się wyrażenie generatora, które przekazuje wartości po jednym na raz do max(). W przypadku niewielkiej liczby przedmiotów nie jest to wielka sprawa, ale w przypadku bardzo dużych słowników dodatkowy wysiłek, aby zbudować listę, a następnie ją zniszczyć, może być znaczny. – steveha

+0

Właśnie zaktualizowałem moją odpowiedź ... przełączono z list na generatory/iteratory –

+2

Po prostu nie potrzebujesz dodatkowych paren. Parens z max() może wykonać podwójne zadanie: mogą być one parens dla wywołania funkcji do max() i mogą być również parens wokół wyrażenia generatora. Spróbuj! :-) – steveha

0

Gdybym cię i prędkość była dużym problemem, ja pewnie stworzyć nową klasę pojemnik „DictMax”, który by śledzić na jego największa wartość niezerową elementy poprzez posiadanie wewnętrznego stosu ind exes, gdzie najwyższym elementem stosu jest zawsze klucz największego elementu w słowniku. W ten sposób za każdym razem otrzymasz największy element w stałym czasie.

Powiązane problemy