如何自定义排序字母数字混合列表?

6
我有以下列表。
l = ['SRATT', 'SRATW', 'CRAT', 'CRA0', 'SRBTT', 'SRBTW', 'SRAT0', 'SRBT0']

我希望按字母顺序排序,并添加以下规则:以数字(实际上始终为0)结尾的字符串必须在最后一个完全按字母表顺序的字符串之后出现(最后一个字母最多是W)。

我应该如何做到这一点?(如果可能,使用简单的方法,如 sorted


对于这个例子列表,期望的结果将是

['CRAT', 'CRA0', 'SRATT', 'SRATW' , 'SRAT0', 'SRBTT', 'SRBTW', 'SRBT0']

例如下面的代码无法正常工作。
sorted(l, key=lambda x: x[-1].isdigit())

自从它将最后一个数字的字符串放在末尾,就像这样。
['SRATT', 'SRATW', 'CRAT', 'SRBTT', 'SRBTW', 'CRA0', 'SRAT0', 'SRBT0']

这些字符串是否包含除字母数字字符以外的其他字符? - Willem Van Onsem
3个回答

6

底部有可行解决方案

第一次尝试:

>>> l = ['SRATT', 'SRATW', 'CRAT', 'CRA0', 'SRBTT', 'SRBTW', 'SRAT0', 'SRBT0']
>>> sorted(l, key=lambda x: (x[:-1], x[-1].isdigit()))
['CRAT', 'CRA0', 'SRATT', 'SRATW', 'SRAT0', 'SRBTT', 'SRBTW', 'SRBT0']

更新

@StefanPochmann指出,如果具有相同的开头和不同的最后一个非数字字符,则此操作将失败。

我们可以在键的末尾添加附加元素,该元素本身将成为元素。

>>> l = ['SRATT', 'SRATW', 'CRAT', 'CRA0', 'SRBTT', 'SRBTW', 'SRAT0', 'SRBT0', 'B', 'A']
>>> sorted(l, key=lambda x: (x[:-1], x[-1].isdigit(), x))
                                                      ^
                                             additional element
['A', 'B', 'CRAT', 'CRA0', 'SRATT', 'SRATW', 'SRAT0', 'SRBTT', 'SRBTW', 'SRBT0']

更新(最终,希望如此)

@Demosthene指出第二个尝试不起作用,这是正确的。

因此,工作解决方案是选择元素末尾的任何数字(如果存在),并将其更改为超出字母和数字范围的符号,例如'{'

sorted(l, key=lambda x: ''.join((x[:-1], '{')) if x[-1].isdigit() else x)

或者

sorted(l, key=lambda x: x[:-1] + '{' if x[-1].isdigit() else x)

如@StefanPochmann所述。这可能会更快一些。

谢谢!我会在几分钟内接受答案(SO现在不允许我这样做...)。 - Demosthene
@StefanPochmann 我已更新答案,现在可以使用单个字符。谢谢。 - vishes_shell
@StefanPochmann,你说得没错,抱歉将你的例子放在错误的问题解释中。 - vishes_shell
1
@vishes_shell,我又发现了一个问题;将元素'SRE'添加到'l'中,并使用sorted(l, key=lambda x: (x[:-1], x[-1].isdigit(), x))实际上会将'SRE'放在'SRATT'之前。你如何进行“绝对”字母排序? - Demosthene
@Demosthene 谢谢,你是对的,我已经更新了答案。:) - vishes_shell
显示剩余4条评论

4

你需要保留字符串的字母标准(除了最后一个元素),并引入另一个标准:以数字结尾。

sorted(l, key=lambda x: (x[:-1] ,x[-1].isdigit()))

更为复杂但更加稳健的方式:
sorted(l, key=lambda x: (x[:-1] if len(x)>1 and not x[-1].isdigit() else x,x[-1].isdigit() if x else False))

(修复了Stefan指出的一种情况,在该情况下,列表由大小为1或0的元素组成,或者是 ['AB', 'AA'] 情况)

你的修复并没有真正修复它,现在它仍然失败,比如['AB', 'AA'] - Stefan Pochmann
你是对的。"仅以0结尾"使得这个答案过于复杂了。如果可以适用于任意位数就更好了。 - Jean-François Fabre

2

以下是另一种简单的方法,只需将0视为Z:

>>> sorted(l, key=lambda x: x.replace('0', 'Z'))
['CRAT', 'CRA0', 'SRATT', 'SRATW', 'SRAT0', 'SRBTT', 'SRBTW', 'SRBT0']

(我假设字符串中没有前导零,如果有错误,请告诉我。)

OP说“数字在结尾”,然后又说“它总是0”,这是真的。 - Jean-François Fabre
@Jean-FrançoisFabre 是的,但这并不排除其他地方有零。 - Stefan Pochmann
在这种情况下执行以下操作:re.sub(r"\d$","Z",x) - Jean-François Fabre
@Jean-FrançoisFabre 是的,或者 re.sub(r"0$","Z",x)。但如果我的假设是正确的,我更喜欢非正则表达式的解决方案。 - Stefan Pochmann

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