Python 使用 operator.itemgetter 对字典进行排序

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4690416/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 16:57:25  来源:igfitidea点击:

Sorting dictionary using operator.itemgetter

pythonsortingdictionary

提问by user225312

A question was asked here on SO, a few minutes ago, on sorting dictionary keys based on their values.

几分钟前,在 SO 上提出了一个问题,即根据字典键的值对其进行排序。

I just read about the operator.itemgettermethod of sorting a few days back and decided to try that, but it doesn't seem to be working.

operator.itemgetter几天前我刚刚阅读了排序方法,并决定尝试一下,但它似乎不起作用。

Not that I have any problems with the answers presented to the questions, I just wanted to try this with operator.itemgetter.

并不是说我对问题的答案有任何问题,我只是想用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:

这就像我想要的那样工作。但是,由于我没有完整的字典 ( mydict.itervalues()),我尝试了以下操作:

>>> 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.itemgetterand call itemgetteron the nested key - value pair.

那么我如何使用operator.itemgetter和调用itemgetter嵌套的键值对对dict 进行排序。

采纳答案by unutbu

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

关键参数始终是一个函数,它一次从 iterable ( mydict.iteritems()) 中获取一项。在这种情况下,一个项目可能是这样的

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

So we need a function that can take ('a2',['e',2])as input and return 2.

所以我们需要一个可以('a2',['e',2])作为输入并返回 2的函数。

lambda (k,v): ...is an anonymous function which takes one argument -- a 2-tuple -- and unpacks it into kand v. So when the lambdafunction is applied to our item, kwould be 'a2'and vwould be ['e',2].

lambda (k,v): ...是一个匿名函数,它接受一个参数——一个 2 元组——并将其解包到kand 中v。因此,当该lambda函数应用于我们的项目时,k将是'a2'v将是['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.

lambda (k,v): operator.itemgetter(1)(v)因此应用于我们的项目返回 operator.itemgetter(1)(['e',2]),它“itemgets” 中的第二个项目['e',2],即 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:

请注意,这lambda (k,v): operator.itemgetter(1)(v)不是在 Python 中编码的好方法。正如 gnibbler 指出的那样,为每个 itemoperator.itemgetter(1)重新计算。那是低效的。使用的重点是创建一个可以多次应用的函数。您不想每次都重新创建该函数。可读性更强,速度更快:operator.itemgetter(1)lambda (k,v): v[1]

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

回答by Sven Marnach

The answer is -- you can't. operator.itemgetter(i)returns a callable that returns the item iof its argument, that is

答案是——你不能。 operator.itemgetter(i)返回一个返回i其参数项的可调用对象,即

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:

它永远不会像d[i][j]. 如果你真的想以纯函数式的方式做到这一点,你可以编写自己的compose()函数:

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 :)

请注意,我不建议这样做:)

回答by John La Rooy

itemgetter doesn't support nesting ( although attrgetter does)

itemgetter 不支持嵌套(尽管 attrgetter 支持)

you'd need to flatten the dict like this

你需要像这样压平字典

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

回答by Mateen Ulhaq

Indexing normally a la kv[1][1]is faster:

索引通常 a lakv[1][1]更快:

>>> from timeit import timeit
>>> setup = 'import operator; g = operator.itemgetter(1); '
>>> setup += 'd = {i: list(range(i+2)) for i in range(100)}'
>>> kwargs = {'setup': setup, 'number': 10000}

>>> timeit('sorted(d.items(), key=lambda kv: kv[1][1])', **kwargs)
0.5251589557155967

>>> timeit('sorted(d.items(), key=lambda kv: g(kv[1]))', **kwargs)
0.7175205536186695

>>> timeit('sorted(d.items(), key=lambda kv: g(kv)[1])', **kwargs)
0.7915238151326776

>>> timeit('sorted(d.items(), key=lambda kv: g(g(kv)))', **kwargs)
0.9781978335231543