2011-01-14 15 views
18

A question was asked here on SO, kilka minut temu, na temat sortowania kluczy słownika na podstawie ich wartości.Sortowanie słownika przy użyciu operatora.itemgetter

Właśnie przeczytałem o sposobie sortowania kilka dni wstecz i postanowiłem spróbować, ale wydaje się, że nie działa.

Nie mam żadnych problemów z odpowiedziami na pytania, chciałem tylko wypróbować to z operator.itemgetter.

Więc DICT było:

>>> mydict = { 'a1': ['g',6], 
      'a2': ['e',2], 
      'a3': ['h',3], 
      'a4': ['s',2], 
      'a5': ['j',9], 
      'a6': ['y',7] } 

Próbowałem to:

>>> l = sorted(mydict.itervalues(), key=operator.itemgetter(1)) 
>>> l 
[['e', 2], ['s', 2], ['h', 3], ['g', 6], ['y', 7], ['j', 9]] 

A działa to tak jak chcemy. Jednak, ponieważ nie mam kompletny słowniku (mydict.itervalues()), próbowałem to:

>>> complete = sorted(mydict.iteritems(), key=operator.itemgetter(2)) 

To nie działa (tak jak się spodziewałem, że).

W jaki sposób posortować dyktę za pomocą operator.itemgetter i zadzwonić pod numer itemgetter w zagnieżdżonej pary klucz-wartość.

Odpowiedz

31
In [6]: sorted(mydict.iteritems(), key=lambda (k,v): operator.itemgetter(1)(v)) 
Out[6]: 
[('a2', ['e', 2]), 
('a4', ['s', 2]), 
('a3', ['h', 3]), 
('a1', ['g', 6]), 
('a6', ['y', 7]), 
('a5', ['j', 9])] 

Kluczowym parametrem jest zawsze funkcja, która jest podawana z jednego elementu z pliku iterowalnego (mydict.iteritems()) naraz. W tym przypadku, element może być coś podobnego

('a2',['e',2]) 

Musimy więc funkcję, która może trwać ('a2',['e',2]) jako wejście i powrót 2.

lambda (k,v): ... jest anonimowa funkcja, która trwa jeden argument - 2- tuple - i rozpakowuje go do k i v. Jeśli więc do naszej pozycji zostanie zastosowana funkcja lambda, k będzie 'a2', a v będzie ['e',2].

lambda (k,v): operator.itemgetter(1)(v) zastosowane do naszej pozycji powraca zatem operator.itemgetter(1)(['e',2]), które „itemgets” druga pozycja w ['e',2], która jest 2.

Zauważ, że lambda (k,v): operator.itemgetter(1)(v) nie jest dobrym sposobem na kod w Pythonie.Jak zauważył gnibbler, operator.itemgetter(1) jest przeliczane dla każdego elementu. To nieefektywne. Celem użycia operator.itemgetter(1) jest utworzenie funkcji, która może być stosowana wiele razy. Nie chcesz ponownie tworzyć funkcji za każdym razem. lambda (k,v): v[1] jest bardziej czytelny i szybciej:

In [15]: %timeit sorted(mydict.iteritems(), key=lambda (k,v): v[1]) 
100000 loops, best of 3: 7.55 us per loop 

In [16]: %timeit sorted(mydict.iteritems(), key=lambda (k,v): operator.itemgetter(1)(v)) 
100000 loops, best of 3: 11.2 us per loop 
+0

Czy możesz wyjaśnić to: 'operator.itemgetter (1) (v))'? – user225312

+3

@A A: 'operator.itemgetter (1) (v)' jest równoważne 'v [1]'. Możesz zastąpić każde wystąpienie 'a [b]' z 'operator.itemgetter (b) (a)', ale nie jest tak, jak * I * zrozumiałem twoje pytanie :) –

+4

Tworzenie itemgettera jest stosunkowo kosztowne. To tworzy jeden dla każdego klucza w dyktafonie –

5

Odpowiedź brzmi - nie możesz. operator.itemgetter(i) zwraca płatnych na żądanie, która zwraca element i swojego argumentu, że jest

f = operator.itemgetter(i) 
f(d) == d[i] 

nigdy nie powróci simething jak d[i][j]. Jeśli naprawdę chcesz to zrobić w stylu czysto funkcjonalny, można napisać własny compose() funkcję:

def compose(f, g): 
    return lambda *args: f(g(*args)) 

i używać

sorted(mydict.iteritems(), key=compose(operator.itemgetter(1), 
             operator.itemgetter(1))) 

pamiętać, że nie polecam to zrobić :)

+0

'unutbu' ma rozwiązanie, choć nie jest jasne. Będziemy czekać na jego aktualizację. – user225312

5

itemgetter nie obsługuje zagnieżdżanie (choć attrgetter robi)

trzeba by spłaszczyć dict jak ten

sorted(([k]+v for k,v in mydict.iteritems()), key=itemgetter(2)) 
+0

+1, Całkiem dobrze! – user225312

Powiązane problemy