如何按照字符串中的数字对字符串列表进行排序?

10

我有一个字符串列表,现在想要按照每个元素中的数字进行排序。使用sorted失败了,因为它无法处理像103之间的顺序。我可以想象如果我使用re,就可以解决这个问题。但是这样不够有趣。你们有什么好的实现想法吗?我假设这段代码是用Python 3.x编写的。

names = [
'Test-1.model',
'Test-4.model',
'Test-6.model',
'Test-8.model',
'Test-10.model',
'Test-20.model'
]
number_sorted = get_number_sorted(names)
print(number_sorted)
'Test-20.model'
'Test-10.model'
'Test-8.model'
'Test-6.model'
'Test-4.model'
'Test-1.model'
7个回答

7

关键在于...这个关键

sorted(names, key=lambda x: int(x.partition('-')[2].partition('.')[0]))

将字符串中的排序部分分离出来并将其转换为整数,以便识别为排序顺序。

5

一些替代方案:

(1) 按位置切片:

sorted(names, key=lambda x: int(x[5:-6]))

(2)剥离子字符串:

sorted(names, key=lambda x: int(x.replace('Test-', '').replace('.model', '')))

或者 更好的(Pandas 版本 >3.9):
x.removeprefix('Test-').removesuffix('.model')

(3) 分割字符 (也可以使用 str.partition 进行分割):

sorted(names, key=lambda x: int(x.split('-')[1].split('.')[0]))

(4)使用np.argsort在(1)-(3)中的任何一个上进行映射:

list(map(names.__getitem__, np.argsort([int(x[5:-6]) for x in names])))

考虑到目标是对原始字符串进行排序,而不仅仅是获取排序后的数字,使用“key”函数执行转换会更有意义(并避免不必要的genexpr),例如对于您的第一个示例,“sorted(names,key = lambda x:int(x [5:-6]))”,或对于您的第二个示例,“sorted(names,key = lambda x:int(x.replace('Test-','').replace('.model','')))”。 - ShadowRanger
@ShadowRanger,是的,我现在意识到了。我已经编辑了我的答案。 - jpp
我喜欢现在的多种选择。那真是创新。 - Back2Basics
自3.9版本以来,x.removeprefix('Test-').removesuffix('.model')可能比.replace版本更合适。str.removeprefix和str.removesuffix的文档 - Stef

3

我自己找到了一个类似的问题和解决方案。 Python中os.listdir()的非字母数字列表顺序

import re
def sorted_alphanumeric(data):
    convert = lambda text: int(text) if text.isdigit() else text.lower()
    alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ] 
    return sorted(data, key=alphanum_key, reverse=True)

2
您可以在sort函数的key中使用re.findall:
import re
names = [
 'Test-1.model',
 'Test-4.model',
 'Test-6.model',
 'Test-8.model',
 'Test-10.model',
 'Test-20.model'
]
final_data = sorted(names, key=lambda x:int(re.findall('(?<=Test-)\d+', x)[0]), reverse=True)

输出:

['Test-20.model', 'Test-10.model', 'Test-8.model', 'Test-6.model', 'Test-4.model', 'Test-1.model']

1
这里有一种基于正则表达式的方法。我们可以从字符串中提取测试编号,转换为整数,然后按照该编号进行排序。
import re

def grp(txt): 
    s = re.search(r'Test-(\d+)\.model', txt, re.IGNORECASE)
    if s:
        return int(s.group(1))
    else:
        return float('-inf')  # Sorts non-matching strings ahead of matching strings

names.sort(key=grp)

这仍然按字符串样式(词典顺序)排序,而不是按数字排序。在第一种情况下,您需要返回int(s.group(1)),并且在else情况下,需要返回一些填充数值(例如float('-inf')以将不匹配模式的字符串排序放在结果列表的前面),而不是str - ShadowRanger
@ShadowRanger 不,即使进行这些更改,仍然无法解决它。顺便说一下,我不懂Python。随意编辑此内容。 - Tim Biegeleisen
@TimBiegeleisen: list.sort 运行在原地且返回 None(即“没有返回值”)。您的测试代码通过将 names = names.sort(key=lambda l: grp(l)) 的结果赋值给 None,因此它失败了。我从中删除了 names =,变成了 names.sort(key=grp)(不需要 lambda 包装器,因为 grp 已经具有正确的原型),然后它正常工作 - ShadowRanger

1
def find_between( s, first, last ):
    try:
        start = s.index( first ) + len( first )
        end = s.index( last, start )
        return s[start:end]
    except ValueError:
        return ""

然后做类似以下的事情:
 sorted(names, key=lambda x: int(find_between(x, 'Test-', '.model')))

1
您可以使用sorted()key参数来完成此操作,假设每个字符串格式相同:
def get_number_sorted(somelist):
    return sorted(somelist, key=lambda x: int(x.split('.')[0].split('-')[1]))

看起来您可能想要将列表进行反向排序(?),在这种情况下,您可以添加reverse=True,如下所示:

def get_number_sorted(somelist):
    return sorted(somelist, key=lambda x: int(x.split('.')[0].split('-')[1]), reverse=True)
number_sorted = get_number_sorted(names)
print(number_sorted)
['Test-20.model', 'Test-10.model', 'Test-8.model', 'Test-6.model', 'Test-4.model', 'Test-1.model']

查看相关内容:关键函数


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接