【问题标题】:Python: How to sort a list of dictionaries by several values?Python:如何按几个值对字典列表进行排序?
【发布时间】:2013-04-11 13:37:53
【问题描述】:

我想首先按一个值对列表进行排序,然后再按第二个值排序。是否有捷径可寻?这是一个小例子:

A = [{'name':'john','age':45},
     {'name':'andi','age':23},
     {'name':'john','age':22},
     {'name':'paul','age':35},
     {'name':'john','age':21}]

此命令用于按'name'对该列表进行排序:

sorted(A, key = lambda user: user['name'])

但是我怎样才能按第二个值对这个列表进行排序呢?就像这个例子中的'age'

我想要这样的排序(首先按'name' 排序,然后按'age' 排序):

andi - 23
john - 21
john - 22
john - 45
paul - 35

谢谢!

【问题讨论】:

  • 另一方面:python 的排序保证是稳定的,因此你可以简单地通过sort age 然后通过name 来获得你的结果通缉。 (请注意,键的顺序是相反的。您首先按第二个键排序,然后按第一个键)。

标签: python list sorting


【解决方案1】:
>>> A = [{'name':'john','age':45},
     {'name':'andi','age':23},
     {'name':'john','age':22},
     {'name':'paul','age':35},
     {'name':'john','age':21}]
>>> sorted(A, key = lambda user: (user['name'], user['age']))
[{'age': 23, 'name': 'andi'}, {'age': 21, 'name': 'john'}, {'age': 22, 'name': 'john'}, {'age': 45, 'name': 'john'}, {'age': 35, 'name': 'paul'}]

这按两个属性的元组排序,以下是等效的并且更快/更干净:

>>> from operator import itemgetter
>>> sorted(A, key=itemgetter('name', 'age'))
[{'age': 23, 'name': 'andi'}, {'age': 21, 'name': 'john'}, {'age': 22, 'name': 'john'}, {'age': 45, 'name': 'john'}, {'age': 35, 'name': 'paul'}]

来自 cmets:@Bakuriu

我敢打赌两者之间没有太大区别,但itemgetter 避免了一点开销,因为它在单个操作码(CALL_FUNCTION)期间提取密钥并生成tuple,同时调用@987654326 @ 必须调用函数,加载各种常量(它们是其他字节码),最后调用下标(BINARY_SUBSCR),构建tuple 并返回它......这对解释器来说还有很多工作要做。

总结一下:itemgetter 将执行完全保持在C 级别,因此它尽可能快。

【讨论】:

  • 我想解释一下为什么 itemgetter 会比 lambda 表达式快得多。它不是归结为相同的查找吗?
  • @catchmeifyoutry 我敢打赌,两者之间没有 的区别,但 itemgetter 避免了一些开销,因为它在单个过程中提取键并生成元组opcode(CALL_FUNCTION),在调用 lambda 时必须调用函数,加载各种常量(这是其他字节码)最后调用下标(BINARY_SUBSCR),构建元组并返回它......这很多口译员的更多工作
  • @Bakuriu 谢谢你的解释。所以itemgetter的实现在cpython中被优化为c代码,而不仅仅是其在线文档中提到的参考python代码实现。
  • @catchmeifyoutry 是的。请注意,文档说它是 equivalent 到那个 python 代码,而不是它是这样实现的。特别是itemgetter 确实是type(参见type(operator.itemgetter)),所以它甚至不是一个真正的函数。这是典型的:很多内置函数都是用 C 实现的,而且它们通常是类型而不是函数(例如 enumerate)。
  • 嗨@jamylak,我没有意识到我们可以使用* 来迭代列表元素以传入itermgetter()。这很棒。它运行良好。非常感谢!
【解决方案2】:
from operator import itemgetter

sorted(your_list, key=itemgetter('name', 'age'))

【讨论】:

  • 您想知道operator.itemgetter 是否会做一些近乎神奇的事情?它不是。它返回一个元组(在这种情况下长度为 2),然后 sorted 用它来 The Right Thing
  • 好答案。但必须像下面这样使用:your_list_sorted = sorted(your_list, key=itemgetter('name','age'))
【解决方案3】:

这是另一种通用解决方案 - 它通过键和值对 dict 的元素进行排序。 它的优点 - 无需指定键,如果某些字典中缺少某些键,它仍然可以工作。

def sort_key_func(item):
    """ helper function used to sort list of dicts

    :param item: dict
    :return: sorted list of tuples (k, v)
    """
    pairs = []
    for k, v in item.items():
        pairs.append((k, v))
    return sorted(pairs)

【讨论】:

    猜你喜欢
    • 2021-08-25
    • 2011-02-22
    • 2010-09-09
    相关资源
    最近更新 更多