问候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找不到任何解释。这种行为有一些潜在的原因吗?在某些情况下它会有用吗?
答案 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
修改强> 解决每个人都说
的问题一旦看到两种不同的类型,就会引发异常
我知道你可能已经意识到这种说法过于简单了,但我认为不清楚,这会引起混淆。
以下示例包含两个类A
和B
,它们通过各自的__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])]
它应该适用于任何数据类型(包括自定义类)