如何有效地排序 Python 包含浮点数和前导 + 或 - 符号的字符串在多个不同的位置

How to efficiently sort Python strings containing floating numbers AND a leading + or - sign at multiple and varying locations

以前的解决方案侧重于数字与字母之间用破折号分隔的字符串 (sorting strings containing numbers and letters) or another consistent delimiter (e.g., '_', )。数字通常与字母位于相同的位置。这些都是比较简单的列表,比如

l=['101-8', '101-8A', '101-9', '102-1', '103-4', '103-4B', '101-10', '101-11','103-10'] 

l=['10_file','11_file','1_file','20_file','21_file','2_file']

我需要对以下内容进行排序:

listfromhell=['a_+10.9.mrc','a_-10.0.mrc','a_-12.0_b.mrc','az_x_y_+60.13_a.hdf','bc_ab_+15.0_rst.mrc']

需要按照-+符号(包括符号)后面的数字排序。

因此,上面列表的正确排序是:

listfromhell=['a_-12.0_b.mrc','a_-10.0.mrc','a_+10.9.mrc','bc_ab_+15.0_rst.mrc','az_x_y_+60.13_a.mrc']

如果用于排序的浮点数(带有前面的 +- 符号)同时出现,则与之前为更简单的列表提出的类似的单行代码效果很好location always,其中 "location" 表示排序元素在列表中出现的索引,该索引是在某种一致的分隔符处拆分每个字符串元素所产生的。

例如,这样的列表:

nicelist=['a_b_-12.0_d.mrc','a_r_+10.9_t_z_y.mrc','c_a_-10.0.mrc','bc_ab_+15.0_rst.mrc','az_x_+60.13_a.mrc']

可以很容易地排序为:

sorted(l, key=lambda s: float(s.split("_")[2].replace('.mrc',''))))

因为在使用一致的分隔符拆分每个字符串后,浮点数总是出现在索引“2”处 '_'

当排序元素出现的索引(nicelist 中的 2)事先未知时,如何实现类似的简单解决方案?

并且这个问题有多个越来越复杂的情况,例如当浮点数出现在随机位置时,当没有一致的分隔符时,以及当混淆 '+''-' 除了浮点数前面的其他地方的符号,以及不属于浮点数的混淆数字。例如,

listfromhellandthensome=['a5-_-12.0b.mrc','a+101.9-.mrc','-a11_-10.0.mrc','b-c_ab_+15.0_rs+t.mrc','a + z_-x_y_+6.10334_a4.mrc']

基本上,最终任务是找到一个优雅的解决方案(单行代码会很棒)来对字符串元素列表进行排序,其中每个元素都包含一个未知的浮点数 size/length和符号(可以是正数也可以是负数)并且可以出现在字符串中的任意位置,没有已知的一致分隔符

谢谢你的想法!

使用正则表达式拆分字符串:

import re

# taken from https://gist.github.com/smac89/bfefc0303c2aab6cac0b08055e195c55
regex = r'.*?([-+](?:\d+\.\d*|\.?\d+)(?:[eE][-+]?\d+)?).*'
compiled = re.compile(regex)

listfromhellandthensome=['a5-_-12.0b.mrc','a+101.9-.mrc','-a11_-10.0.mrc','b-c_ab_+15.0_rs+t.mrc','a + z_-x_y_+6.10334_a4.mrc']

print (sorted(listfromhellandthensome, key=lambda s: float(compiled.sub(r'', s))))

输出:

['a5-_-12.0b.mrc', '-a11_-10.0.mrc', 'a + z_-x_y_+6.10334_a4.mrc',
'b-c_ab_+15.0_rs+t.mrc', 'a+101.9-.mrc']

上面的正则表达式匹配 -.0-4.+5.0-3.e3+5.2E-1 等值。基本上任何有效的浮点值在 python 中被识别。这可能是也可能不是你想要的,但我只是让你知道。

您只需从每个字符串中提取 float/int 以及符号(+-),然后将提取的部分传递到 float()函数和排序。

所以我想出的正则表达式 (regex101) 是:

(\+|-)\d+(\.\d+)?

所以我们检查 float/int 前面是否有 +- 然后尽可能多地匹配到小数点 (.)然后尽可能多的小数点 - 只有在有小数点的情况下。最后一部分 ("only if there is") 只需使用 ? 即可实现 - 表示出现 01 次。

所以现在要将此应用于 Python,使用您的列表 l,并且已经 运行 import re,您可以使用这一行对其进行排序:

l.sort(key = lambda s: float(re.search('(\+|-)\d+(\.\d+)?', s).group()))

对于最后一个例子,l 为:

['a5-_-12.0b.mrc', '-a11_-10.0.mrc', 'a + z_-x_y_+6.10334_a4.mrc', 'b-c_ab_+15.0_rs+t.mrc', 'a+101.9-.mrc']

我认为是正确的!


对于 listfromhell 示例,这实现了预期的输出:

['a_-12.0_b.mrc', 'a_-10.0.mrc', 'a_+10.9.mrc', 'bc_ab_+15.0_rst.mrc', 'az_x_y_+60.13_a.hdf']