Python sort different types in list
我需要使用python 3对列表进行排序。可能有
我目前正在尝试使用这样的
1 2 3 4 5 6 7 8 9 10 11 | data.sort(key=gen_key) ... def gen_key(self, value): if is_number(value): return str(value) if isinstance(value, str): return value return '___' + type(value).__name__ |
但问题是现在数字将被自然排序。当我想要排序数字和浮点数时,仍然像数字和浮点数一样,而不是将它们作为字符串进行线程化。
这种行为是由
1 | unordarable types: int() < str() |
号
有什么建议吗?
诀窍是让您的
虽然与python 2所做的并不完全相同,但对于特定的"前面的数字,其他所有与typename比较的内容",您可以使用一个相当有效的
1 2 3 4 | >>> 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)] |
这里的
这里的主要缺陷是,类似于
它也不会处理递归的情况;如果序列包含
如果这不是一个问题,那么运行起来就便宜,而且相对简单。
与使用定义为执行比较的
时间安排:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # 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级别
最干净的方法是将对象用作排序键,该对象在其比较方法中包含所需的排序行为。python排序所需的唯一比较方法是
例如,这里有一个类,它大致实现了python 2排序启发式(在可比较的对象组中按值排序)。当然,你可以执行你喜欢的任何其他规则。由于排序将为列表中的每个项目创建这些对象中的一个,我通过使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from sys import intern class Py2Key: __slots__ = ("value","typestr") def __init__(self, value): self.value = value self.typestr = intern(type(value).__name__) def __lt__(self, other): try: return self.value < other.value except TypeError: return self.typestr < other.typestr |
使用:
1 2 3 | seq = ["Z", 3,"Y", 1,"X", 2.5, False] sorted(seq, key=Py2Key) >>> [False, 1, 2.5, 3, 'X', 'Y', 'Z'] |
号
不幸的是,在python 3中实现python 2的排序行为将比python2慢,而且内存密集,特别是因为我们利用了异常处理。这在您的应用程序中是否可以接受取决于您自己。