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

时间:2011-01-14 11:11:25

标签: python sorting dictionary

几分钟前,

A question was asked here on SO根据值对字典键进行排序。

我刚刚读过关于几天前排序的operator.itemgetter方法,并决定尝试一下,但它似乎没有用。

并非我对问题的答案有任何问题,我只是想用operator.itemgetter来尝试。

所以dict是:

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

我试过了:

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

这就像我想要的那样。但是,由于我没有完整的字典(mydict.itervalues()),我试过这个:

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

这不起作用(正如我所料)。

那么如何使用operator.itemgetter对dict进行排序并在嵌套键值对上调用itemgetter

5 个答案:

答案 0 :(得分:30)

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

key参数始终是一次从iterable(mydict.iteritems())中提供一个项目的函数。在这种情况下,项目可能类似于

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

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

lambda (k,v): ...是一个匿名函数,它接受一个参数 - 一个2元组 - 并将其解压缩到kv。因此,当lambda函数应用于我们的项目时,k将为'a2'v将为['e',2]

lambda (k,v): operator.itemgetter(1)(v)应用于我们的项目因此返回 operator.itemgetter(1)(['e',2]),其中“itemgets”['e',2]中的第二项,即2。

请注意,lambda (k,v): operator.itemgetter(1)(v)不是用Python编写代码的好方法。正如gnibbler指出的那样,operator.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

答案 1 :(得分:5)

答案是 - 你做不到。 operator.itemgetter(i)返回一个callable,返回其参数的项i,即

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

它永远不会返回像d[i][j]这样的东西。如果您真的想以纯粹的功能性方式执行此操作,则可以编写自己的compose()函数:

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

并使用

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

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

答案 2 :(得分:5)

itemgetter不支持嵌套(尽管attrgetter确实如此)

你需要像这样压扁字典

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

答案 3 :(得分:0)

通常为kv[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

答案 4 :(得分:0)

解包元组参数的功能在Python 3中已删除:请参见PEP 3113

因此,接受的答案对运行python 3.x的人不起作用:

等效的解决方案是

sorted(mydict.items(),key=lambda kv:operator.itemgetter(1)(kv[1]) )