Sorting dictionary using operator.itemgetter
Solution 1
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])]
The key parameter is always a function that is fed one item from the iterable (mydict.iteritems()
) at a time. In this case, an item could be something like
('a2',['e',2])
So we need a function that can take ('a2',['e',2])
as input and return 2.
lambda (k,v): ...
is an anonymous function which takes one argument -- a 2-tuple -- and unpacks it into k
and v
. So when the lambda
function is applied to our item, k
would be 'a2'
and v
would be ['e',2]
.
lambda (k,v): operator.itemgetter(1)(v)
applied to our item thus returns
operator.itemgetter(1)(['e',2])
, which "itemgets" the second item in ['e',2]
, which is 2.
Note that lambda (k,v): operator.itemgetter(1)(v)
is not a good way to code in Python. As gnibbler points out, operator.itemgetter(1)
is recomputed for each item. That's inefficient. The point of using operator.itemgetter(1)
is to create a function that can be applied many times. You don't want to re-create the function each time. lambda (k,v): v[1]
is more readable, and faster:
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
Solution 2
The answer is -- you can't. operator.itemgetter(i)
returns a callable that returns the item i
of its argument, that is
f = operator.itemgetter(i)
f(d) == d[i]
it will never return simething like d[i][j]
. If you really want to do this in a purely functional style, you can write your own compose()
function:
def compose(f, g):
return lambda *args: f(g(*args))
and use
sorted(mydict.iteritems(), key=compose(operator.itemgetter(1),
operator.itemgetter(1)))
Note that I did not recommend to do this :)
Solution 3
itemgetter doesn't support nesting ( although attrgetter does)
you'd need to flatten the dict like this
sorted(([k]+v for k,v in mydict.iteritems()), key=itemgetter(2))
Related videos on Youtube
user225312
Updated on November 25, 2020Comments
-
user225312 over 3 years
A question was asked here on SO, a few minutes ago, on sorting dictionary keys based on their values.
I just read about the
operator.itemgetter
method of sorting a few days back and decided to try that, but it doesn't seem to be working.Not that I have any problems with the answers presented to the questions, I just wanted to try this with
operator.itemgetter
.So the dict was:
>>> mydict = { 'a1': ['g',6], 'a2': ['e',2], 'a3': ['h',3], 'a4': ['s',2], 'a5': ['j',9], 'a6': ['y',7] }
I tried this:
>>> l = sorted(mydict.itervalues(), key=operator.itemgetter(1)) >>> l [['e', 2], ['s', 2], ['h', 3], ['g', 6], ['y', 7], ['j', 9]]
And this works as I want it to. However, since I don't have the complete dictionary (
mydict.itervalues()
), I tried this:>>> complete = sorted(mydict.iteritems(), key=operator.itemgetter(2))
This doesn't work (as I expected it to).
So how do I sort the dict using
operator.itemgetter
and callitemgetter
on the nested key - value pair. -
user225312 over 13 yearsCan you please explain this:
operator.itemgetter(1)(v))
? -
user225312 over 13 years
unutbu
has a solution, though it's not clear. We will wait for him to update it. -
Sven Marnach over 13 years@A A:
operator.itemgetter(1)(v)
is equivalent tov[1]
. You can replace just any occurrence ofa[b]
withoperator.itemgetter(b)(a)
, but this is not how I did understand your question :) -
John La Rooy over 13 yearsCreating an itemgetter is relatively expensive. This creates one for each key in the dict
-
ezdazuzena over 10 yearsfor python3 use items instead of iteritems
-
Zelphir Kaltstahl about 6 yearsInvalid syntax anyway, because
lambda
does not take the tuple. -
Mateen Ulhaq over 5 yearsI think it would be valuable to put a disclaimer at the top lest the naive Google searcher unwittingly think's it's cool to use that