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

Lexicographically sort deeply nested lists of mixed data types in Python 3

在python 3中,list.sort()方法将执行词典编纂排序。但是在python 3中,将一个列表与floatint进行比较会抛出一个TypeError,这与python 2不同,在这里可以做到:

1
2
>>> [0, 1] < 2
False

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

我试过对list进行子类化,但要使其生效,每个嵌套列表都必须强制转换为子类类型,以便所有嵌套的比较都使用重写的比较方法。有没有一种方法可以做到这一点,而不需要递归地将每个嵌套列表转换为子类?

我想能够比较两个列表,如下所示:

1
2
3
4
>>> 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相同的排序函数,除非将listfloatint进行比较,在这种情况下,应始终将list视为更大的排序函数。


因为,正如python 2文档中提到的那样:

Most other objects of built-in types compare unequal unless they are
the same object; the choice whether one object is considered smaller
or larger than another one is made arbitrarily but consistently within
one execution of a program.

只有当两个对象属于同一类型时,对象比较才有意义。依赖于表达式(如[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。

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

或者,对于list.sort()。

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

如果您想要产生一个有意义的排序(如果这确实有意义),那么您必须定义一个键函数,正如前面提到的那样。不过,这可能相当复杂。也许从不同的角度来看待你的问题会更好。


这条路很慢。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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来实现。


正确的解决方案不是子类list,而是简单地使用sort方法的key参数来定义自定义键函数:

1
sorted(l, key=custom_key_function)

custom_key_function(list_element)应该为该列表元素生成一个标准化的键,所有键都属于同一类。

在不知道您的列表可能包含哪些类型的元素的情况下,我不会推测如何实现它的进一步细节,但我认为从您的示例中可以公平地说,您可能需要使用相同的custom_key_function递归地对子列表排序。