【问题标题】:Sort a list of dictionary with order of specific key按特定键的顺序对字典列表进行排序
【发布时间】:2020-03-28 07:44:54
【问题描述】:

我有一个 listdict 是这样的:

data = [{"uid": "a1", "name": "b1"}, 
        {"uid": "a3", "name": "b3"}, 
        {"uid": "a4", "name": "b4"},
        {"uid": "a5", "name": "b5"}]

现在我想按照 uid 字段的顺序对 list 进行排序,如下所示:

uid_order = ['a1', 'a5', 'a3', 'a4']

这意味着输出应该是:

[{"uid": "a1", "name": "b1"}, 
 {"uid": "a5", "name": "b5"},
 {"uid": "a3", "name": "b3"},
 {"uid": "a4", "name": "b4"}]

当然,我可以创建一个新的空 list,然后使用 2 个 for 循环来检查和添加每个元素,但是有什么优雅的方法(或更好的复杂性)来做到这一点?

【问题讨论】:

  • 不,这个答案只有在 uid_order 已经处于降序/升序时才有效
  • 我明白了。糟糕的是,我在阅读问题时看到了我期望看到的内容,应该已经看到了您要求的特定顺序。将标题更新为“按非标准顺序对字典列表进行排序”可能会有所改进吗?如果他们有我认为的相同问题,其他人会更容易找到。

标签: python python-3.x sorting dictionary


【解决方案1】:

O(n) 解:

>>> [*map({d['uid']: d for d in data}.get, uid_order)]
[{'uid': 'a1', 'name': 'b1'},
 {'uid': 'a5', 'name': 'b5'},
 {'uid': 'a3', 'name': 'b3'},
 {'uid': 'a4', 'name': 'b4'}]

【讨论】:

  • list(...) 可以说比[*...] 更干净,但这非常整洁
  • @MadPhysicist 我以前也这么认为,但我已经习惯了[*...],我喜欢它与[2, 3, 5][<list comp>] 的一致性。也许有一天每个人都会使用它,当然除了那些今天仍然写set([...]) insted of {...} 的人 :-)
【解决方案2】:

如果您想避免创建新列表,可以使用 sort 方法对列表进行适当的排序。这将使用具有 O(n log n) 复杂性的 Timsort,比您建议的 O(n^2) 实现要好得多:

uid_order = {k: i for i, k in enumerate(uid_order)}
data.sort(key=uid_order.get)

为了加快查找uid_order,我将其反转为字典(反转是因为列表将索引映射到项目,而您希望项目到索引)。您现在有一个 O(1) 查找,而不是在每次评估密钥时查找 O(n)

另一种仅使用函数调用来制作字典的方法:

uid_order = dict(map(reversed, enumerate(uid_order)))

另见:Python Sorting HOW TO

【讨论】:

【解决方案3】:

使用sorted-函数,您可以指定该函数应该排序的键。您想要访问每个字典的 "uid" 键的值,并且该值在 uid_order 中的索引决定了该字典在排序列表中的索引:

sorted(data, key = lambda x: uid_order.index(x["uid"]))

这段代码的意思是,列表的每个元素都被传递给lambda-函数。结果值用作排序后的键。

【讨论】:

  • 非常好,我喜欢一行代码,但不幸的是我正在寻找更好的性能,所以我不得不接受@Mad Physicist 解决方案,对此感到抱歉:D
猜你喜欢
  • 1970-01-01
  • 2011-04-03
  • 2017-02-28
  • 2021-10-27
  • 2015-08-09
  • 2017-04-08
  • 2014-02-11
  • 2018-10-24
  • 1970-01-01
相关资源
最近更新 更多