2012-11-21 18 views
8

Chcę zamówić elementy w słowniku przy użyciu różnych funkcji porównawczych. Proszę zobaczyć mój przykładowy kod poniżej. Jest to ostatnia część używająca funkcji cmpRatio z sortowanym(), która nie działa. Nie jestem pewien, co robię źle. Z góry dziękuję za każdy pomysł!posortowana funkcja pytona z zdefiniowanymi przez użytkownika funkcjami cmp

mydict = { 'a1': (1,6), 
      'a2': (10,2), 
      'a3': (5,3), 
      'a4': (1,2), 
      'a5': (3,9), 
      'a6': (9,7) } 

# sort by first element of the value tuple: WORKS 
print sorted(mydict.iteritems(), key=lambda (k,v): v[0]) 

# sort by second element of the value tuple: WORKS 
print sorted(mydict.iteritems(), key=lambda (k,v): v[1]) 

# THIS is what I can't get working: 
def cmpRatio(x,y): 
    sx = float(x[0])/x[1] 
    sy = float(y[0])/y[1] 
    return sx < sy 

# sort by sum of the elements in the value tuple: DOES NOT WORK 
print sorted(mydict.iteritems(), key=lambda (k,v): v, cmp=cmpRatio) 
+0

spróbuj sformatować kod za mało '{}' pudełko na edytorze –

Odpowiedz

6

Unikaj cmp funkcji tam, gdzie to możliwe, ponieważ są one wolne. Muszą być ponownie ocenione dla każdego porównania. Użycie klucza key powoduje, że klucz musi zostać obliczony tylko jeden raz.

print sorted(mydict.iteritems(), key=lambda (k,v): float(v[0])/v[1]) 

Mówisz również, że chcesz sortować według sumy pozycji wartościowych, ale sortujesz według różnicy. Suma będzie wyglądać następująco:

print sorted(mydict.iteritems(), key=lambda (k,v): sum(v)) 

Jak wspomniano w innych odpowiedzi, w celu naprawdę chcąc zdefiniować cmp funkcja, nie wracają właściwą wartość (musi być -1,0 lub 1).

return cmp(sx,sy) 

Ale także jeśli tylko przy użyciu lambda, aby uzyskać wartość, można zastąpić, że z itemgetter które powinny być szybciej niż funkcja python-side:

from operator import itemgetter 

print sorted(mydict.iteritems(), key=itemgetter(1), cmp=cmpRatio) 

Jeśli próbujesz zapisać operacje sortowania, byłoby znacznie lepiej przechowywać najważniejsze funkcje:

key_ops = { 
    'sum': lambda (k,v): sum(v), 
    'ratio': lambda (k,v): float(v[0])/v[1]), 
} 

def print_op(aDict, opName): 
    print sorted(aDict.iteritems(), key=key_ops[opName]) 

... # some place later in code 
print_op(mydict, 'sum') 
+0

Przepraszam za zamieszanie, sumy oraz współczynnika gdzie dwa różnych funkcji komparatora, z których chcę korzystać. Twoje rozwiązanie działa doskonale, ale mój przykład jest nie tylko powolny, po prostu nie działa, i nadal chcę zrozumieć, co robię źle. Chcę móc definiować funkcje komparatora i używać ich jako parametrów do innej funkcji optymalizacji, to jest podstawowy powód, dla którego próbuję używać cmp. Dzięki! –

+0

@RuxandraPalmtag: Nadal nie wiem, dlaczego chciałbyś funkcję 'cmp'. Powinieneś raczej zdefiniować wiele operacji 'lambda' dla klucza. Ale zaktualizowałem swoją funkcję 'cmp'. – jdi

+0

Och, rozumiem teraz: wartość zwracana, czytam o tym, ale się nie zarejestrowałem :) Dziękuję za komentarz wydajnościowy, spróbuję użyć klucza z lambda i zobaczyć jak działa z moim kodem! –

2

Jeśli chcesz, aby posortować według sumy wartości krotki (według Twojego komentarza), można użyć:

print sorted(mydict.iteritems(), key=lambda v: sum(v[1])) 

Jeśli chcesz sortować według wskaźnika (zgodnie z kodem):

print sorted(mydict.iteritems(), key=lambda v: float(v[1][0])/v[1][1]) 
4

you funkcja porównanie powinno się (/ negatywny/pozytywny zerową) wartość zwracana, gdy pierwszy ARGUM ent jest (mniejszy/równy/większy niż) drugą wartością (w przeciwieństwie do komparatora podanego pod adresem std::sort(...) w C++).

czyli zamiast

return sx < sy 

zrobić

return cmp(sx,sy) 
Powiązane problemy