Python:列表包含不同元素类型时的list.sort()查询

时间:2014-01-01 19:22:31

标签: python list sorting python-3.x

问候Pythonic世界。学习Python 3.3的第4天,我遇到了list.sort的奇怪属性。

我创建了一个包含五个元素的列表:四个字符串,中间有一个数字。由于混合类型,尝试让list.sort工作会产生预期的错误:

>>> list = ['b', 'a', 3, 'd', 'c']
>>> list.sort()
Traceback (innermost last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: int() < str()
>>> list
['b', 'a', 3, 'd', 'c']

列表没有变化。

然后我将数字移到最后,再次使用list.sort,得到了这个:

>>> list = ['b', 'a', 'd', 'c', 3]
>>> list.sort()
Traceback (innermost last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: int() < str()
>>> list
['a', 'b', 'c', 'd', 3]

好的,错误。但是这个列表已经自行排序,将数字踢到最后。我在这个网站或Langtangen找不到任何解释。这种行为有一些潜在的原因吗?在某些情况下它会有用吗?

5 个答案:

答案 0 :(得分:9)

来自Python 3 docs

  

此方法仅使用&lt;对该列表进行排序。两者之间的比较   项目。如果有任何比较操作,则不会禁止例外   失败,整个排序操作将失败(列表可能会失败   处于部分修改状态)。

文档并不特别保证任何行为,但元素很可能会被部分排序。当异常发生时,他们所处的顺序,并且此顺序可能在实现之间变化,或者可能(但不太可能)两次后续运行程序。

如果您想尝试对项目进行排序而不必担心不幸的重新排序,您可以使用sorted内置函数,它将返回一个新列表而不是修改原始列表。

>>> seq = ['b', 'a', 3, 'd', 'c']
>>> try:
...     seq = sorted(seq) # if sorted fails, result won't be assigned
... except Exception: # you may only want TypeError
...     pass
...
>>> seq 
['b', 'a', 3, 'd', 'c'] # list unmodified

修改 解决每个人都说

的问题
  

一旦看到两种不同的类型,就会引发异常

我知道你可能已经意识到这种说法过于简单了,但我认为不清楚,这会引起混淆。

以下示例包含两个类AB,它们通过各自的__lt__方法支持相互比较。它显示了以list.sort()排序的这两种类型的混合列表,然后按排序顺序打印,没有异常引发:

class A:
    def __init__(self, value):
        self.a = value

    def __lt__(self, other):
        if isinstance(other, B):
            return self.a < other.b
        else:
            return self.a < other.a

    def __repr__(self):
        return repr(self.a)

class B:
    def __init__(self, value):
        self.b = value

    def __lt__(self, other):
        if isinstance(other, A):
            return self.b < other.a
        else:
            return self.b < other.b

    def __repr__(self):
        return repr(self.b)

seq = [A(10), B(2), A(8), B(16), B(9)]
seq.sort()
print(seq)

这个输出是:

[2, 8, 9, 10, 16]

了解这一切的每一个细节并不重要。这只是为了说明如果所有部分都在那里,混合类型列表可以与list.sort()一起使用

答案 1 :(得分:2)

这并不罕见。简单地sort()不检查列表是否包含一致的数据类型,而是尝试进行排序。因此,一旦你的元素结束,最近会对它进行分析,因此算法在发现错误之前对列表的一部分进行了排序。

不 - 它没用,因为它在很大程度上取决于实现的排序机制。

答案 2 :(得分:2)

取决于数据需要如何排序,但这样的事情可以起作用

l = ['a',3,4,'b']
sorted([str(x) for x in l])
['3', '4', 'a', 'b']

答案 3 :(得分:1)

我写下面的答案是假设我知道列表中的数据类型,可能效率不高。我的想法是根据数据类型将给定列表划分为子列表,然后对每个列表进行排序并组合。

input= ['b', 'a', 3, 'd', 'c']
strs = list(filter(lambda x : type(x) ==str,input))
ints = list(filter(lambda x: type(x) == int, input))

output = sorted(strs) + sorted(ints)

答案 4 :(得分:1)

我最近遇到了同样的问题,不想将所有内容都转换为字符串,所以我这样做了,希望它有所帮助:)

list = ["a", 1, False, None, "b", (1,3), (1, 'a'),(1, [None, False]), True, 3, False]

type_weights = {}
for element in list:
    if type(element) not in type_weights:
        type_weights[type(element)] = len(type_weights)

print(sorted(list, key=lambda element: (type_weights[type(element)], str(element))))

它应该返回如下内容: ['a', 'b', 1, 3, False, False, True, None, (1, 'a'), (1, 3), (1, [None, False])]

它应该适用于任何数据类型(包括自定义类)