我有一个字符串列表,我想执行一个自然的字母排序。
例如,下面的列表是自然排序(我想要的):
['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13']
下面是上面列表的“排序”版本(我使用sorted()得到的):
['Elm11', 'Elm12', 'Elm2', 'elm0', 'elm1', 'elm10', 'elm13', 'elm9']
我在寻找一个排序函数它的行为和第一个一样。
我有一个字符串列表,我想执行一个自然的字母排序。
例如,下面的列表是自然排序(我想要的):
['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13']
下面是上面列表的“排序”版本(我使用sorted()得到的):
['Elm11', 'Elm12', 'Elm2', 'elm0', 'elm1', 'elm10', 'elm13', 'elm9']
我在寻找一个排序函数它的行为和第一个一样。
当前回答
a = ['H1', 'H100', 'H10', 'H3', 'H2', 'H6', 'H11', 'H50', 'H5', 'H99', 'H8']
b = ''
c = []
def bubble(bad_list):#bubble sort method
length = len(bad_list) - 1
sorted = False
while not sorted:
sorted = True
for i in range(length):
if bad_list[i] > bad_list[i+1]:
sorted = False
bad_list[i], bad_list[i+1] = bad_list[i+1], bad_list[i] #sort the integer list
a[i], a[i+1] = a[i+1], a[i] #sort the main list based on the integer list index value
for a_string in a: #extract the number in the string character by character
for letter in a_string:
if letter.isdigit():
#print letter
b += letter
c.append(b)
b = ''
print 'Before sorting....'
print a
c = map(int, c) #converting string list into number list
print c
bubble(c)
print 'After sorting....'
print c
print a
应答:
气泡排序作业
如何在python中一次读一个字母的字符串
其他回答
在@Mark Byers的回答之后,这里有一个接受关键参数的适应,并且更符合pep8。
def natsorted(seq, key=None):
def convert(text):
return int(text) if text.isdigit() else text
def alphanum(obj):
if key is not None:
return [convert(c) for c in re.split(r'([0-9]+)', key(obj))]
return [convert(c) for c in re.split(r'([0-9]+)', obj)]
return sorted(seq, key=alphanum)
我还做了一个Gist
data = ['elm13', 'elm9', 'elm0', 'elm1', 'Elm11', 'Elm2', 'elm10']
让我们分析一下数据。所有元素的数字容量为2。在常见的字面部分“elm”中有3个字母。
所以,元素的最大长度是5。我们可以增加这个值以确保(例如,增加到8)。
记住这一点,我们有一个简单的解决方案:
data.sort(key=lambda x: '{0:0>8}'.format(x).lower())
没有正则表达式和外部库!
print(data)
>>> ['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'elm13']
解释:
for elm in data:
print('{0:0>8}'.format(elm).lower())
>>>
0000elm0
0000elm1
0000elm2
0000elm9
000elm10
000elm11
000elm13
上面的答案对于上面给出的具体例子是有用的,但对于更普遍的自然排序问题,却遗漏了几个有用的例子。我刚刚被其中一个案例咬了一口,所以想出了一个更彻底的解决方案:
def natural_sort_key(string_or_number):
"""
by Scott S. Lawton <scott@ProductArchitect.com> 2014-12-11; public domain and/or CC0 license
handles cases where simple 'int' approach fails, e.g.
['0.501', '0.55'] floating point with different number of significant digits
[0.01, 0.1, 1] already numeric so regex and other string functions won't work (and aren't required)
['elm1', 'Elm2'] ASCII vs. letters (not case sensitive)
"""
def try_float(astring):
try:
return float(astring)
except:
return astring
if isinstance(string_or_number, basestring):
string_or_number = string_or_number.lower()
if len(re.findall('[.]\d', string_or_number)) <= 1:
# assume a floating point value, e.g. to correctly sort ['0.501', '0.55']
# '.' for decimal is locale-specific, e.g. correct for the Anglosphere and Asia but not continental Europe
return [try_float(s) for s in re.split(r'([\d.]+)', string_or_number)]
else:
# assume distinct fields, e.g. IP address, phone number with '.', etc.
# caveat: might want to first split by whitespace
# TBD: for unicode, replace isdigit with isdecimal
return [int(s) if s.isdigit() else s for s in re.split(r'(\d+)', string_or_number)]
else:
# consider: add code to recurse for lists/tuples and perhaps other iterables
return string_or_number
测试代码和几个链接(在StackOverflow上和关闭)在这里: http://productarchitect.com/code/better-natural-sort.py
欢迎您的反馈。这并不是一个明确的解决方案;只是向前迈出了一步。
本职位的价值
我的观点是提供一个可以普遍应用的非正则表达式解决方案。 我将创建三个函数:
find_first_digit,这是我从@AnuragUniyal借来的。它将查找字符串中第一个数字或非数字的位置。 Split_digits是一个生成器,它将字符串分成数字块和非数字块。当它是数字时,它也会产生整数。 Natural_key只是将split_digits包装成一个元组。这是我们用来排序,最大,最小的键。
功能
def find_first_digit(s, non=False):
for i, x in enumerate(s):
if x.isdigit() ^ non:
return i
return -1
def split_digits(s, case=False):
non = True
while s:
i = find_first_digit(s, non)
if i == 0:
non = not non
elif i == -1:
yield int(s) if s.isdigit() else s if case else s.lower()
s = ''
else:
x, s = s[:i], s[i:]
yield int(x) if x.isdigit() else x if case else x.lower()
def natural_key(s, *args, **kwargs):
return tuple(split_digits(s, *args, **kwargs))
我们可以看到它是一般的,因为我们可以有多个数字块:
# Note that the key has lower case letters
natural_key('asl;dkfDFKJ:sdlkfjdf809lkasdjfa_543_hh')
('asl;dkfdfkj:sdlkfjdf', 809, 'lkasdjfa_', 543, '_hh')
或保留大小写敏感:
natural_key('asl;dkfDFKJ:sdlkfjdf809lkasdjfa_543_hh', True)
('asl;dkfDFKJ:sdlkfjdf', 809, 'lkasdjfa_', 543, '_hh')
我们可以看到它以适当的顺序对OP的列表进行排序
sorted(
['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13'],
key=natural_key
)
['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13']
但它也可以处理更复杂的列表:
sorted(
['f_1', 'e_1', 'a_2', 'g_0', 'd_0_12:2', 'd_0_1_:2'],
key=natural_key
)
['a_2', 'd_0_1_:2', 'd_0_12:2', 'e_1', 'f_1', 'g_0']
我的正则表达式等价于
def int_maybe(x):
return int(x) if str(x).isdigit() else x
def split_digits_re(s, case=False):
parts = re.findall('\d+|\D+', s)
if not case:
return map(int_maybe, (x.lower() for x in parts))
else:
return map(int_maybe, parts)
def natural_key_re(s, *args, **kwargs):
return tuple(split_digits_re(s, *args, **kwargs))
现在是一些更优雅的东西(pythonic)
-只要碰一下
有很多实现,虽然有些已经接近,但没有一个能完全捕获现代python所提供的优雅。
使用python测试(3.5.1) 包含了一个额外的列表,以演示当 数字在字符串中间 没有测试,但是,我假设如果您的列表是相当大的,那么事先编译正则表达式会更有效 如果这是一个错误的假设,我相信有人会纠正我
罢工
from re import compile, split
dre = compile(r'(\d+)')
mylist.sort(key=lambda l: [int(s) if s.isdigit() else s.lower() for s in split(dre, l)])
完整代码
#!/usr/bin/python3
# coding=utf-8
"""
Natural-Sort Test
"""
from re import compile, split
dre = compile(r'(\d+)')
mylist = ['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13', 'elm']
mylist2 = ['e0lm', 'e1lm', 'E2lm', 'e9lm', 'e10lm', 'E12lm', 'e13lm', 'elm', 'e01lm']
mylist.sort(key=lambda l: [int(s) if s.isdigit() else s.lower() for s in split(dre, l)])
mylist2.sort(key=lambda l: [int(s) if s.isdigit() else s.lower() for s in split(dre, l)])
print(mylist)
# ['elm', 'elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13']
print(mylist2)
# ['e0lm', 'e1lm', 'e01lm', 'E2lm', 'e9lm', 'e10lm', 'E12lm', 'e13lm', 'elm']
使用时注意
从操作系统。路径导入分割 您需要区分导入
灵感来自
Python文档-如何排序 人类排序:自然排序顺序 人的分类 这篇文章的贡献者/评论员和引用帖子