我有一个我想要自然排序的字符串列表:
c = ['0', '1', '10', '11', '2', '2Y', '3', '3Y', '4', '4Y', '5', '5Y', '6', '7', '8', '9', '9Y']
除了自然排序,我想将所有非纯数字字符串的条目移到最后。我的预期输出是:
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '2Y', '3Y', '4Y', '5Y', '9Y']
请注意,一切都必须被纳入 - 甚至是字母数字字符串。
我知道我可以使用natsort
包来获得我想要的东西,但仅凭这一点并不适合我。我需要使用两个排序调用来执行此操作 - 一个用于自然排序,另一个用于将非纯数字字符串移动到最后。
import natsort as ns
r = sorted(ns.natsorted(c), key=lambda x: not x.isdigit())
print(r)
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '2Y', '3Y', '4Y', '5Y', '9Y']
我想知道是否可以以狡猾的方式使用natsort
并将其减少为单个排序调用。
答案 0 :(得分:4)
natsort
有一个函数 natsort_key
,可以根据完成的排序将项目转换为元组。
所以你可以用它作为:
sorted(c, key=lambda x: (not x.isdigit(), *ns.natsort_key(x)))
这会产生:
>>> sorted(c, key=lambda x: (not x.isdigit(), *ns.natsort_key(x)))
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '2Y', '3Y', '4Y', '5Y', '9Y']
您也可以在没有可迭代解包的情况下使用它,因为在这种情况下我们有两个2元组,并且如果第一个项目有抢占式,它将比较natsort_key
调用的结果:
sorted(c, key=lambda x: (not x.isdigit(), ns.natsort_key(x)))
答案 1 :(得分:2)
我非常感谢Willem Van Onsem发表他的回答。但是,我应该注意到原始功能的性能要快一个数量级。考虑到PM2 Ring的建议,这两种方法之间有一些基准:
<强>设置强>
c = \
['0',
'1',
'10',
'11',
'2',
'2Y',
'3',
'3Y',
'4',
'4Y',
'5',
'5Y',
'6',
'7',
'8',
'9',
'9Y']
d = c * (1000000 // len(c) + 1) # approximately 1M elements
%timeit sorted(d, key=lambda x: (not x.isdigit(), ns.natsort_key(x)))
1 loop, best of 3: 2.78 s per loop
Original (w/ PM 2Ring's enhancement)
%timeit sorted(ns.natsorted(d), key=str.isdigit, reverse=True)
1 loop, best of 3: 796 ms per loop
对原始版本的高性能的解释是因为Tim Sort似乎针对几乎排序的列表进行了高度优化。
完整性检查
x = sorted(d, key=lambda x: (not x.isdigit(), ns.natsort_key(x)))
y = sorted(ns.natsorted(d), key=str.isdigit, reverse=True)
all(i == j for i, j in zip(x, y))
True
答案 2 :(得分:2)
您可以使用natsorted
和正确选择的key
来实际执行此操作。
>>> ns.natsorted(d, key=lambda x: (not x.isdigit(), x))
['0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'10',
'11',
'2Y',
'3Y',
'4Y',
'5Y',
'9Y']
该键返回一个元组,原始输入为第二个元素。数字字符串放在前面,所有其他字符串放在后面,然后子集被单独排序。
作为旁注,Willem Van Onsem's solution使用的natsort_key
已从natsort
3.0.4版开始弃用(如果您在翻译中打开DeprecationWarning
,则会{看到了,该功能现在没有记录)。它实际上效率很低......最好使用返回自然排序键的natort_keygen
。 natsort_key
在引擎盖下调用它,因此对于每个输入,您都要创建一个新函数,然后再调用一次。
下面我重复显示here所显示的测试,并使用natsorted
方法添加我的解决方案,并使用natsort_keygen
代替natsort_key
添加其他解决方案的时间
In [13]: %timeit sorted(d, key=lambda x: (not x.isdigit(), ns.natsort_key(x)))
1 loop, best of 3: 33.3 s per loop
In [14]: natsort_key = ns.natsort_keygen()
In [15]: %timeit sorted(d, key=lambda x: (not x.isdigit(), natsort_key(x)))
1 loop, best of 3: 11.2 s per loop
In [16]: %timeit sorted(ns.natsorted(d), key=str.isdigit, reverse=True)
1 loop, best of 3: 9.77 s per loop
In [17]: %timeit ns.natsorted(d, key=lambda x: (not x.isdigit(), x))
1 loop, best of 3: 23.8 s per loop