在python中使用字母和数字排序列表



请帮我处理一下列表我有一个列表名

arr = [{'name':'cator3'}
{'name':'cator1'}
{'name':'CATOR5 (Active A)'},
{'name':'cator17'},
{'name':'cator12'},
{'name':'cator4'},
{'name':'CATOR5 (Passive A)'},
{'name':'cator23'},
{'name':'cator2'}]

每个字典都有一个包含字符和数字的名称。我处理了排序结果

我代码:

def sort_order_by(e):
order_by = 'name'
return e[order_by].lower()
sort='asc'
if sort == 'asc':
arr.sort(key=sort_order_by)
elif sort == 'desc':
arr.sort(key=sort_order_by, reverse=True)

print(arr) 

和我的结果:

result = [{'name': 'cator1'},
{'name': 'cator12'},
{'name': 'cator17'},
{'name': 'cator2'},
{'name': 'cator23'},
{'name': 'cator3'},
{'name': 'cator4'},
{'name': 'CATOR5 (Active A)'},
{'name': 'CATOR5 (Passive A)'}]

您可以看到初始文本后面的数字之间的错误排列:

cator1, cator12, cator17, cator2, cator23, cator3…

But 2 <3 & lt;12 & lt;17 & lt;23日

我希望数字和字母都有正确的结果

我期望的结果是按字母和数字顺序排列的

expected = [{'name': 'cator1'},
{'name': 'cator2'},
{'name': 'cator3'},
{'name': 'cator4'},
{'name': 'CATOR5 (Active A)'},
{'name': 'CATOR5 (Passive A)'},
{'name': 'cator12'},
{'name': 'cator17'},
{'name': 'cator23'},]

如何获得正确的排序顺序?

如果您可以使用外部库,我强烈推荐natsort。一旦你运行了pip install natsortconda install natsort或类似的,你可以执行

from natsort import natsorted, ns
arr = natsorted(arr, alg=ns.IGNORECASE, reverse=sort == 'desc')

如果需要就地排序,可以生成一个排序键并与arr.sort一起使用:

from natsort import natsort_keygen, ns
arr.sort(key=natsort_keygen(alg=ns.IGNORECASE), reverse=sort == 'desc')

免责声明:我不是natsort的作者,也没有任何关联。虽然我确实修正了文档中的一个小错字,有一次。

您可以使用正则表达式替换对长度为10的字符串的数字部分进行右对齐。这将使它们在字符串的字母数字顺序中正确排序(按数字顺序)。

这可以使用lambda作为re.sub()中的替换值来实现:

arr = [{'name':'cator3'},
{'name':'cator1'},
{'name':'CATOR5 (Active A)'},
{'name':'cator17'},
{'name':'cator12'},
{'name':'cator4'},
{'name':'CATOR5 (Passive A)'},
{'name':'cator23'},
{'name':'cator2'}]
import re
arr.sort(key=lambda d: re.sub(r'd*', 
lambda n: f"{n.group():>10}",
d['name'].lower()))
print(*arr,sep='n')
{'name': 'cator1'}
{'name': 'cator2'}
{'name': 'cator3'}
{'name': 'cator4'}
{'name': 'CATOR5 (Active A)'}
{'name': 'CATOR5 (Passive A)'}
{'name': 'cator12'}
{'name': 'cator17'}
{'name': 'cator23'}

如果你要在不同的字典列表和/或使用不同的键经常这样做,你可以为它创建一个实用程序函数:

import re
def alpha_num(k):
return lambda d: re.sub(r'd*',lambda n: f"{n.group():>10}",d[k].lower())
arr.sort(key=alpha_num('name'))

下面是一个简短的示范示例,逐步完成该过程。值得注意的是,这是一个任意的排序规范,并没有试图太聪明。

还假设字符串长度为5,后跟一个数字。如果愿意,可以使用正则表达式或类似的过程(或文字迭代)来标识字符串。你也可以更进一步,建立一个更普遍的关系(尽管听起来你并不关心这个)。

arr=[
{'name':'cator3'},
{'name':'cator1'},
{'name':'CATOR5 (Active A)'},
{'name':'cator17'},
{'name':'cator12'},
{'name':'cator4'},
{'name':'CATOR5 (Passive A)'},
{'name':'cator23'},
{'name':'cator2'}
]
def sort_order_by(e):
order_by = 'name'
key = e[order_by].lower()              ; print(key, "->", end=' ')
split = key.split()
rest = ' '.join(split[1:])
key = split[0]                         ; print(key, "->", end=' ')
key, nkey = key[:5], key[5:]           ; print(key, nkey, "->", end=' ')
nkey = f"{int(nkey):05}"               ; print(key + nkey + rest)
return key + nkey + rest
sort_type = 'asc'
arr.sort(key=sort_order_by, reverse=(sort_type == 'desc'))

[print(x) for x in arr]

输出:

cator3 -> cator3 -> cator 3 -> cator00003
cator1 -> cator1 -> cator 1 -> cator00001
cator5 (active a) -> cator5 -> cator 5 -> cator00005(active a)
cator17 -> cator17 -> cator 17 -> cator00017
cator12 -> cator12 -> cator 12 -> cator00012
cator4 -> cator4 -> cator 4 -> cator00004
cator5 (passive a) -> cator5 -> cator 5 -> cator00005(passive a)
cator23 -> cator23 -> cator 23 -> cator00023
cator2 -> cator2 -> cator 2 -> cator00002
{'name': 'cator1'}
{'name': 'cator2'}
{'name': 'cator3'}
{'name': 'cator4'}
{'name': 'CATOR5 (Active A)'}
{'name': 'CATOR5 (Passive A)'}
{'name': 'cator12'}
{'name': 'cator17'}
{'name': 'cator23'}