我正在尝试对包含数字和字母的列表进行排序:
names = ["5aG", "6bG", "10cG", "J1", ...]
输出应如下所示:
['5aG', '5bG', '5aR', '5bR', '6aG', '6bG', '6cG', '6aR', '6bR', '7aG', '7bG', '7aR', '8aG', '8bG', '8aR', '9aG', '9bG', '9aR','10aG', '10bG', '10cG', '10aR', 'J1', 'J2']
字符串的第一个元素总是一个5-10的数字,然后有一个来自a-c的字母,最后还有另一个字母(“G”或“R”)。
此外还有字符串“J1”和“J2”。它们应该始终是最后的(“J2”之前的“J1”)。
我怎样才能实现这样的目标?我想过使用lambda函数。
到目前为止,我对它进行了硬编码,但我认为应该有更好的解决方案 这是我的硬编码版本:
classes = ['5aG', '5bG', '5aR', '5bR', '6aG', '6bG', '6cG', '6aR', '6bR', '7aG', '7bG', '7aR', '8aG', '8bG', '8aR', '9aG', '9bG', '9aR','10aG', '10bG', '10cG', '10aR', 'J1', 'J2']
def s(v):
"""Get index of element in list"""
try:
return classes.index(v)
except ValueError:
return 500
l = ['5bG', '6aG', '6bG', '8aR', '9aG', '9bG', '9aR', '10cG', '10aR', 'J1', 'J2', '5aG', '']
w = sorted( l, key=s)
print(w)
答案 0 :(得分:1)
你可以试试这个:
加扰你想要的输出后:
import re
s = ['5aR', '7aR', '10aR', '10cG', '9bG', '8aR', '8bG', '6bR', '5aG', '9aG', 'J1', '6aR', '6aG', '5bR', '7aG', '7bG', '9aR', '5bG', 'J2', '6bG', '10bG', '8aG', '10aG', '6cG']
c, d, *h = sorted(s, key=lambda x:[False if not x[0].isdigit() else int(re.findall('^\d+', x)[0]), x[-1], x[-2]])
sorted_result = [*h, c, d]
输出:
['5aG', '5bG', '5aR', '5bR', '6aG', '6bG', '6cG', '6aR', '6bR', '7aG', '7bG', '7aR', '8aG', '8bG', '8aR', '9aG', '9bG', '9aR', '10aG', '10bG', '10cG', '10aR', 'J1', 'J2']
答案 1 :(得分:1)
您可以使用re
提取前整数,然后依靠tuple
比较。
import re
def key(s):
num, letters = re.match(r'(\d*)(.*)', s).groups()
return float(num or 'inf'), letters
sorted_names = sorted(names, key=key)
请注意,您可以依靠float('inf')
将没有前缀数字的令牌推到最后。
答案 2 :(得分:0)
这是一种方式。
lst = ['7aR', '9aG', '7bG', '10cG', '5bG', '6aG', '6bG', '10bG', 'J2', '5aR', '10aG', '9bG', '6aR', '7aG', '10aR', '9aR', '8aR', 'J1', '5bR', '6bR', '5aG', '8bG', '6cG', '8aG']
sorted([i for i in lst if i[0]!='J'], key=lambda x: [int(x[:-2]), x[-1], x[-2]]) + \
sorted(i for i in lst if i[0]=='J')
# ['5aG', '5bG', '5aR', '5bR', '6aG', '6bG', '6cG', '6aR', '6bR', '7aG', '7bG', '7aR', '8aG', '8bG', '8aR', '9aG', '9bG', '9aR', '10aG', '10bG', '10cG', '10aR', 'J1', 'J2']
答案 3 :(得分:0)
最简单的方法是使用Python的内置排序功能。通过提供合适的函数作为key
参数,您可以按照您选择的任何顺序对事物进行排序。
在内部,当您提供键功能时,sort会生成一个包含两元素元组的列表。元组的第一个元素是一个排序键,即将键函数应用于第二个元素的结果,即列表中的值。然后它对这些元组进行排序,并返回第二个元素的列表。这被称为decorate-sort-undecorate。
您的大部分字符串都是整数,后跟两个字母。您希望最后显示的余数为"J1"
或"J2"
。以下应该是一个合适的关键功能。我采取预防措施将int
函数应用于数字,以确保它们按数字排序而不是按词典排序(因为'2' > '10'
)。
def key_func(s):
# Ensure J-strings are at the end
if s.startswith('J'):
return (1000000, 'J', int(s[1:]))
else:
# The rest, split into digits and two characters
return (int(s[:-2]), s[-2], s[-1])
使用数据的随机副本进行测试
的结果data = ['8aG', '5aR', '6aG', '10aG', '6cG', '8bG', '9aG',
'5aG', '6bG', '7aR', 'J1', '10cG', '10bG', '10aR',
'6bR', 'J2', '6aR', '8aR', '7aG', '9aR', '5bR',
'9bG', '7bG', '5bG']
print(sorted(data, key=key_func))
似乎是正确的(插入换行符以提高可读性):
['5aG', '5aR', '5bG', '5bR', '6aG', '6aR', '6bG', '6bR',
'6cG', '7aG', '7aR', '7bG', '8aG', '8aR', '8bG', '9aG',
'9aR', '9bG', '10aG', '10aR', '10bG', '10cG', 'J1', 'J2']
答案 4 :(得分:0)
使用自定义compound_sort()
功能:
import re
lst = ['9bG', '9aR', 'J2', '7bG', '7aG', '6bR', 'J1', '6cG', '6aG', '6bG', '5bG', '5aG', '8bG', '5bR', '8aR', '5aR', '10aR', '6aR', '10bG', '10aG', '9aG', '10cG', '7aR', '8aG']
pat = re.compile(r'(\d+)(.*)|(J)(\d+)')
def compound_sort(t):
t = tuple(filter(None, t)) # filter empty(None) matches
return (int(t[0]),) + t[1:] if t[0] != 'J' else (float('inf'), t[1])
result = sorted(lst, key=lambda x: compound_sort(pat.search(x).groups()))
print(result)
输出:
['5aG', '5aR', '5bG', '5bR', '6aG', '6aR', '6bG', '6bR', '6cG', '7aG', '7aR', '7bG', '8aG', '8aR', '8bG', '9aG', '9aR', '9bG', '10aG', '10aR', '10bG', '10cG', 'J1', 'J2']