【问题标题】:How do I sort a list with "Nones last"如何使用“最后一个”对列表进行排序
【发布时间】:2013-11-08 21:25:38
【问题描述】:

我正在按键对字典列表进行排序:

groups = sorted(groups, key=lambda a: a['name'])

一些字典的名称设置为None,Python 2 将None 值放在任何其他值之前,因此它们被放置在排序列表的前面。一个天真的解决方法是

groups = sorted(groups, key=lambda a: a['name'] or 'zzzz')

但是,显然,这不适用于任何非拉丁名称。

对包含None 值的列表进行排序以便将这些值放置在列表末尾的方法是什么?

【问题讨论】:

  • FWIW,使用您创建的自定义类的列表,将使这变得微不足道。

标签: python list sorting


【解决方案1】:

您可以通过在元组上键入它来做到这一点:

groups = sorted(groups, key=lambda a: (a['name'] is None, a['name']))

这是因为 Python 按字典顺序比较元组(在第一个元素上,然后在第二个元素上打破关系),并且因为 False 比 True 更早排序。类似的组列表

[{'name': 0}, {'name': 1}, {'name': 2}, {'name': 3}, {'name': 4}, {'name': None}]

会变成

[(False, 0), (False, 1), (False, 2), (False, 3), (False, 4), (True, None)]

True 开头的元组必然会在最后结束,其余的,因为第一个值并列,将按第二个值排序。

【讨论】:

  • 我很确定官方文档中的Sorting HOW TO 在某处解释了这一点。即使没有,这仍然是一种明显的方法,只是不太明显。 :)
  • 确实非常聪明,谢谢 :) 虽然代码中 10 个字符的更改需要 4 行 cmets 来解释它是如何工作的 :))
【解决方案2】:

您可以创建自己的“无限”对象:

from functools import total_ordering

@total_ordering
class Infinity:
    def __eq__(self, other):
        return type(other) == Infinity
    def __lt__(self, other):
        return False

像这样使用它:

>>> lis = [{'name': 1}, {'name': None}, {'name': 0}, {'name': 2}]
>>> sorted(lis, key=lambda a: Infinity() if a['name'] is None else a['name'])
[{'name': 0}, {'name': 1}, {'name': 2}, {'name': None}]

【讨论】:

  • 这也是一个不错的解决方案,尽管对我的用例来说可能有点矫枉过正
  • 虽然可能比元组解决方案更有效:键更小,并且(可能)比较两个非无名称的常见情况与元组进行了额外的比较。虽然差距不大,风格更重要。我个人认为这是极少数可以证明单例的情况之一。
猜你喜欢
  • 1970-01-01
  • 2013-09-02
  • 2012-06-01
  • 1970-01-01
  • 2015-03-31
  • 1970-01-01
  • 1970-01-01
  • 2018-01-24
  • 1970-01-01
相关资源
最近更新 更多