按字典顺序在Python 3中对嵌套的混合数据类型列表进行排序

时间:2014-06-18 17:12:59

标签: python list sorting python-3.x comparison

在Python 3中,list.sort()方法将进行词典排序。但是在Python 3中,将列表与floatint进行比较会引发TypeError,与Python 2不同,您可以在其中执行此操作:

>>> [0, 1] < 2
False

实现旧Python 2行为的最佳方法是什么?

我已经尝试了子类化list,但为了实现这一点,必须将每个嵌套列表强制转换为子类类型,以便所有嵌套比较都使用重写的比较方法。有没有一种方法可以实现这一点,而不是通过递归方式将每个嵌套列表转换为子类?

我希望能够像这样比较两个列表:

>>> a = [[[0, 1], [2, 3]], [0, 1]]
>>> b = [[0, 1], [2, 3]]
>>> a < b
False

结果应该是False,因为a[0][0]listb[0][0]int,在我的情况下int应该是始终被视为小于list

编辑:

我希望实现一个与内置Python 3 list.sort相同的排序函数,除非将listfloat或{进行比较{1}},在这种情况下,int应始终被视为更大。

3 个答案:

答案 0 :(得分:1)

as mentioned in the Python 2 docs

以来
  

内置类型的大多数其他对象比较不相等,除非它们是   同一个对象;选择是否一个对象被认为更小   或大于另一个是任意但一致的   一次执行程序。

对象比较仅在两个对象属于同一类型时才有意义。依赖于诸如[0, 1] < 2之类的表达式返回的值不应该在程序中完成,这就是为什么从Python 3中删除了这种行为的原因。

为了进一步解释,如果你有列表[[[0, 1], [2, 3]], [0, 1]],这有两个要素:
[[0, 1], [2, 3]] and [0, 1]。为了让python对它们进行排序,它会按字典顺序比较它们的内部值,因为它们都是第一个值为[0, 1] and [2, 3]且第二个值为0 and 1的列表。但是,它必须比较[0, 1] with 0,它们不是同一类型,因此,比较会产生任意结果。

因此,此排序已被破坏。

如上所述,如果你有一些可以有意义地排序的列表和一些不能排序的列表(由于上面的解释),一个简单的解决方案是捕获可能的异常,然后返回False。

try:
    [0, 1] < 2
except TypeError:
    # return or assign False. True is not actually meaningful.

或者,对于list.sort()

try:
    x.sort()
except TypeError:
    pass    # Do nothing. Python would produce meaningless results, anyway.

如果你想产生一个有意义的排序(如果这实际上有意义),那么你必须定义一个关键功能,如前所述。但这可能相当复杂。也许从不同的角度看你的问题会更好。

答案 1 :(得分:0)

正确的解决方案不是要list的子类,而只是use the key parameter of the sort method to define a custom key function

sorted(l, key=custom_key_function)

custom_key_function(list_element)应为该list-element生成标准化密钥,所有密钥都属于同一类。

如果不确切知道您的列表可能包含哪些元素,我就不会推测如何实现它的更多详细信息,但我认为从您的示例中可以说您可能需要这样做是公平的。使用相同的custom_key_function递归地对子列表进行排序。

答案 2 :(得分:0)

这是一个缓慢的方式。

要在不可比较的类型AB之间添加顺序,请将它们的实例放在元组中:

a = [[[0, 1], [2, 3]], [0, 1]]
b = [[0, 1], [2, 3]]

def deep_annotate(item):
    if isinstance(item, list):
        return (1, [deep_annotate(i) for i in item])
    else:
        return (0, item)

deep_annotate(a) < deep_annotate(b)
#>>> False

deep_annotate(a) > deep_annotate(b)
#>>> True

不幸的是,很多这不是捷径,可以通过巧妙地使用cmp_to_key来实现。