诀窍是让你的key
函数在第一个索引中返回一个保证可比类型的元组,并在后续索引中返回不同类型的元组。
虽然不是100%相同的都是Python 2呢,为你的具体情况“号码前,一切由类型名称相比,”你可以用一个合理有效key
功能做到这一点:
>>> from numbers import Number
>>> seq = ['Z', 3, 'Y', 1, 'X', 2.5, False, (1, 2), [2, 3], None]
>>> sorted(seq, key=lambda x: (x is not None, '' if isinstance(x, Number) else type(x).__name__, x))
[None, False, 1, 2.5, 3, [2, 3], 'X', 'Y', 'Z', (1, 2)]
这里的key
函数使得key
的第一个元素简单地为bool
,迫使None
在其他所有事情(Py2做同样的事情)之前排序,然后通过使用空字符串为键的第二部分首先排序所有数字类型,其中一切都使用他们的类型名称(也像Py2)。一旦你超过了前两个指数,剩下的就是相同的类型,并且应该比较好。
这里的主要缺陷是set
和frozenset
等可比较的非数字类型不会相互比较,它们将仅按类型名排序(使用异常的自定义键类可以处理此问题)。
它也不会处理递归的情况;如果序列包含[2, 3]
和['a', 'b']
,它将有一个TypeError
比较2
和'a'
,但是没有什么可以用一个可笑的关键类来处理。
如果这不是问题,这是运行便宜,相对简单。
不同于涉及的自定义类与定义执行比较__lt__
解决方案,该方法具有产生内置键,其与所述排序中的Python的高级代码的最小有效地执行比较的优点。
时序:
# Multiply out the sequence so log n factor in n log n work counts for something
>>> seq = ['Z', 3, 'Y', 1, 'X', 2.5, False, (1, 2), [2, 3], None] * 100
# Verify equivalence
>>> sorted(seq, key=Py2Key) == sorted(seq, key=lambda x: (x is not None, '' if isinstance(x, Number) else type(x).__name__, x))
True
# Timings in seconds for the fastest time (of 3 trials) to run the sort 1000 times:
>>> import timeit
# Py2Key class
>>> min(timeit.repeat('sorted(seq, key=Py2Key)', 'from __main__ import seq, Py2Key', number=1000))
5.251885865057375
>>> min(timeit.repeat('sorted(seq, key=lambda x: (x is not None, "" if isinstance(x, Number) else type(x).__name__, x))', 'from __main__ import seq, Number', number=1000))
1.9556877178131344
基本上,避免动态的Python级__lt__
的开销是由刚刚超过60%减少的运行时间。它似乎没有算法上的改进(一个seq
具有相同的运行时间比率的100倍),只是减少了固定开销,但这是一个不小的缩减。
你期待什么结果?你期望如何排序字符串和元组? – jprockbelly
你会怎么样?''''与'13'排序?您需要提出明确的排序顺序。一旦你完成了,你几乎已经完成了。 –