Does Python have a built in function for string natural sort?
使用python 3.x,我有一个字符串列表,我希望对其执行自然的字母排序。
自然排序:窗口中文件的排序顺序。
例如,以下列表是自然排序的(我想要的):
1 | ['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13'] |
这是上面列表的"排序"版本(我拥有的内容):
1 | ['Elm11', 'Elm12', 'Elm2', 'elm0', 'elm1', 'elm10', 'elm13', 'elm9'] |
我在找一个类似于第一个的排序函数。
Pypi上有一个名为natsort的第三方库(完全公开,我是包的作者)。对于您的案例,您可以执行以下任一操作:
1 2 3 4 5 6 | >>> from natsort import natsorted, ns >>> x = ['Elm11', 'Elm12', 'Elm2', 'elm0', 'elm1', 'elm10', 'elm13', 'elm9'] >>> natsorted(x, key=lambda y: y.lower()) ['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13'] >>> natsorted(x, alg=ns.IGNORECASE) # or alg=ns.IC ['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13'] |
您应该注意,
如果需要排序键而不是排序函数,请使用以下公式之一。
1 2 3 4 5 6 7 8 9 10 11 | >>> from natsort import natsort_keygen, ns >>> l1 = ['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13'] >>> l2 = l1[:] >>> natsort_key1 = natsort_keygen(key=lambda y: y.lower()) >>> l1.sort(key=natsort_key1) >>> l1 ['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13'] >>> natsort_key2 = natsort_keygen(alg=ns.IGNORECASE) >>> l2.sort(key=natsort_key2) >>> l2 ['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13'] |
试试这个:
1 2 3 4 5 6 | import re def natural_sort(l): 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(l, key = alphanum_key) |
输出:
1 | ['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13'] |
看它在网上工作:Ideone。
从这里改编的代码:人类排序:自然排序顺序。
下面是马克·拜尔答案的一个更为Python式的版本:
1 2 3 4 5 | import re def natural_sort_key(s, _nsre=re.compile('([0-9]+)')): return [int(text) if text.isdigit() else text.lower() for text in _nsre.split(s)] |
现在,这个函数可以用作任何使用它的函数的键,如
作为一个lambda:
1 | lambda s: [int(t) if t.isdigit() else t.lower() for t in re.split('(\d+)', s)] |
我写了一个基于http://www.codingsurror.com/blog/2007/12/sorting-for-humans-natural-sort-order.html的函数,它增加了传递自己的"key"参数的能力。为了执行包含更复杂对象(不仅仅是字符串)的自然列表,我需要这样做。
1 2 3 4 5 6 7 8 9 10 11 | import re def natural_sort(list, key=lambda s:s): """ Sort the list into natural alphanumeric order. """ def get_alphanum_key_func(key): convert = lambda text: int(text) if text.isdigit() else text return lambda s: [convert(c) for c in re.split('([0-9]+)', key(s))] sort_key = get_alphanum_key_func(key) list.sort(key=sort_key) |
例如:
1 2 3 4 | my_list = [{'name':'b'}, {'name':'10'}, {'name':'a'}, {'name':'1'}, {'name':'9'}] natural_sort(my_list, key=lambda x: x['name']) print my_list [{'name': '1'}, {'name': '9'}, {'name': '10'}, {'name': 'a'}, {'name': 'b'}] |
1 | data = ['elm13', 'elm9', 'elm0', 'elm1', 'Elm11', 'Elm2', 'elm10'] |
让我们分析一下数据。所有元素的位数容量为2。共有3个字母,文字部分为
所以,元素的最大长度是5。我们可以增加这个值以确保(例如,到8)。
考虑到这一点,我们有一个一线解决方案:
1 | data.sort(key=lambda x: '{0:0>8}'.format(x).lower()) |
没有正则表达式和外部库!
1 2 3 | print(data) >>> ['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'elm13'] |
说明:
1 2 3 4 5 6 7 8 9 10 11 | for elm in data: print('{0:0>8}'.format(elm).lower()) >>> 0000elm0 0000elm1 0000elm2 0000elm9 000elm10 000elm11 000elm13 |
鉴于:
1 | data=['Elm11', 'Elm12', 'Elm2', 'elm0', 'elm1', 'elm10', 'elm13', 'elm9'] |
与Sergo的解决方案类似,没有外部库的1行程序将是:
1 | data.sort(key=lambda x : int(x[3:])) |
或
1 | sorted_data=sorted(data, key=lambda x : int(x[3:])) |
说明:
此解决方案使用排序的关键特性来定义将用于排序的函数。因为我们知道每个数据条目前面都有"elm",所以排序函数将字符串中第3个字符后的部分(即int(x[3:]))转换为整数。如果数据的数字部分位于不同的位置,那么函数的这一部分就必须更改。
干杯
现在,为了更优雅的东西(Python)——只需轻轻一点
外面有很多实现,虽然有些实现已经接近尾声,但没有一个完全捕捉到现代Python所提供的优雅。
- 使用python测试(3.5.1)
- 包括一个附加列表,以证明它在数字是中间字符串
- 但是,我没有测试,我假设如果您的列表足够大,那么预先编译regex会更有效率。
- 如果这是一个错误的假设,我相信会有人纠正我。
快的
1 2 3 | 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)]) |
全码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #!/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'] |
使用时注意
from os.path import split - 你需要区分进口商品
灵感来自
- python文档-排序方法
- 人类分类:自然分类顺序
- 人类分类
- 投稿人/评论员
一种选择是将字符串转换为元组,并使用扩展格式http://wiki.answers.com/q/what_expanded_form_means替换数字。
这样A90会变成("A",90,0),A1会变成("A",1)
下面是一些示例代码(由于它从数字中删除前导0的方式,因此效率不是很高)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | alist=["something1", "something12", "something17", "something2", "something25and_then_33", "something25and_then_34", "something29", "beta1.1", "beta2.3.0", "beta2.33.1", "a001", "a2", "z002", "z1"] def key(k): nums=set(list("0123456789")) chars=set(list(k)) chars=chars-nums for i in range(len(k)): for c in chars: k=k.replace(c+"0",c) l=list(k) base=10 j=0 for i in range(len(l)-1,-1,-1): try: l[i]=int(l[i])*base**j j+=1 except: j=0 l=tuple(l) print l return l print sorted(alist,key=key) |
输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ('s', 'o', 'm', 'e', 't', 'h', 'i', 'n', 'g', 1) ('s', 'o', 'm', 'e', 't', 'h', 'i', 'n', 'g', 10, 2) ('s', 'o', 'm', 'e', 't', 'h', 'i', 'n', 'g', 10, 7) ('s', 'o', 'm', 'e', 't', 'h', 'i', 'n', 'g', 2) ('s', 'o', 'm', 'e', 't', 'h', 'i', 'n', 'g', 20, 5, 'a', 'n', 'd', '_', 't', 'h', 'e', 'n', '_', 30, 3) ('s', 'o', 'm', 'e', 't', 'h', 'i', 'n', 'g', 20, 5, 'a', 'n', 'd', '_', 't', 'h', 'e', 'n', '_', 30, 4) ('s', 'o', 'm', 'e', 't', 'h', 'i', 'n', 'g', 20, 9) ('b', 'e', 't', 'a', 1, '.', 1) ('b', 'e', 't', 'a', 2, '.', 3, '.') ('b', 'e', 't', 'a', 2, '.', 30, 3, '.', 1) ('a', 1) ('a', 2) ('z', 2) ('z', 1) ['a001', 'a2', 'beta1.1', 'beta2.3.0', 'beta2.33.1', 'something1', 'something2', 'something12', 'something17', 'something25and_then_33', 'something25and_then_34', 'something29', 'z1', 'z002'] |
这篇文章的价值
我的观点是提供一个可以普遍应用的非正则表达式解决方案。我将创建三个函数:
功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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)) |
我们可以看到,通常我们可以有多个数字块:
1 2 3 4 | # Note that the key has lower case letters natural_key('asl;dkfDFKJ:sdlkfjdf809lkasdjfa_543_hh') ('asl;dkfdfkj:sdlkfjdf', 809, 'lkasdjfa_', 543, '_hh') |
或视情况而定:
1 2 3 | natural_key('asl;dkfDFKJ:sdlkfjdf809lkasdjfa_543_hh', True) ('asl;dkfDFKJ:sdlkfjdf', 809, 'lkasdjfa_', 543, '_hh') |
我们可以看到它按适当的顺序对操作列表进行排序。
1 2 3 4 5 6 | sorted( ['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13'], key=natural_key ) ['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13'] |
但它也可以处理更复杂的列表:
1 2 3 4 5 6 | 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'] |
我的雷杰克斯相当于
1 2 3 4 5 6 7 8 9 10 11 12 | 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)) |
基于这里的答案,我编写了一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | # Copyright (C) 2018, Benjamin Drung <[email protected]> # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED"AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import re def natural_sorted(iterable, key=None, reverse=False): """Return a new naturally sorted list from the items in *iterable*. The returned list is in natural sort order. The string is ordered lexicographically (using the Unicode code point number to order individual characters), except that multi-digit numbers are ordered as a single character. Has two optional arguments which must be specified as keyword arguments. *key* specifies a function of one argument that is used to extract a comparison key from each list element: ``key=str.lower``. The default value is ``None`` (compare the elements directly). *reverse* is a boolean value. If set to ``True``, then the list elements are sorted as if each comparison were reversed. The :func:`natural_sorted` function is guaranteed to be stable. A sort is stable if it guarantees not to change the relative order of elements that compare equal --- this is helpful for sorting in multiple passes (for example, sort by department, then by salary grade). """ prog = re.compile(r"(\d+)") def alphanum_key(element): """Split given key in list of strings and digits""" return [int(c) if c.isdigit() else c for c in prog.split(key(element) if key else element)] return sorted(iterable, key=alphanum_key, reverse=reverse) |
源代码也可以在我的Github代码段存储库中找到:https://github.com/bdrung/snippets/blob/master/natural_sorted.py
最有可能的情况是,
在cpython 2.x下,即使没有实现各自的富比较运算符,也可以对不同类型的对象进行排序。在cpython 3.x下,不同类型的对象必须显式支持比较。看看python如何比较string和int?链接到官方文件。大多数答案都依赖于这种隐含的顺序。切换到python 3.x需要一个新的类型来实现和统一数字和字符串之间的比较。
1 2 3 | Python 2.7.12 (default, Sep 29 2016, 13:30:34) >>> (0,"foo") < ("foo",0) True |
1 2 3 4 5 | Python 3.5.2 (default, Oct 14 2016, 12:54:53) >>> (0,"foo") < ("foo",0) Traceback (most recent call last): File"<stdin>", line 1, in <module> TypeError: unorderable types: int() < str() |
有三种不同的方法。第一种使用嵌套类来利用Python的
排序字符被复制以强制按大小写排序,大小写交换以强制小写字母优先排序;这是"自然排序"的典型定义。我无法决定分组的类型;有些人可能更喜欢以下类型,这也带来了显著的性能优势:
1 | d = lambda s: s.lower()+s.swapcase() |
如果使用比较运算符,则将其设置为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | import functools import itertools @functools.total_ordering class NaturalStringA(str): def __repr__(self): return"{}({})".format\ ( type(self).__name__ , super().__repr__() ) d = lambda c, s: [ c.NaturalStringPart("".join(v)) for k,v in itertools.groupby(s, c.isdigit) ] d = classmethod(d) @functools.total_ordering class NaturalStringPart(str): d = lambda s:"".join(c.lower()+c.swapcase() for c in s) d = staticmethod(d) def __lt__(self, other): if not isinstance(self, type(other)): return NotImplemented try: return int(self) < int(other) except ValueError: if self.isdigit(): return True elif other.isdigit(): return False else: return self.d(self) < self.d(other) def __eq__(self, other): if not isinstance(self, type(other)): return NotImplemented try: return int(self) == int(other) except ValueError: if self.isdigit() or other.isdigit(): return False else: return self.d(self) == self.d(other) __le__ = object.__le__ __ne__ = object.__ne__ __gt__ = object.__gt__ __ge__ = object.__ge__ def __lt__(self, other): return self.d(self) < self.d(other) def __eq__(self, other): return self.d(self) == self.d(other) __le__ = object.__le__ __ne__ = object.__ne__ __gt__ = object.__gt__ __ge__ = object.__ge__ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | import functools import itertools @functools.total_ordering class NaturalStringB(str): def __repr__(self): return"{}({})".format\ ( type(self).__name__ , super().__repr__() ) d = lambda s:"".join(c.lower()+c.swapcase() for c in s) d = staticmethod(d) def __lt__(self, other): if not isinstance(self, type(other)): return NotImplemented groups = map(lambda i: itertools.groupby(i, type(self).isdigit), (self, other)) zipped = itertools.zip_longest(*groups) for s,o in zipped: if s is None: return True if o is None: return False s_k, s_v = s[0],"".join(s[1]) o_k, o_v = o[0],"".join(o[1]) if s_k and o_k: s_v, o_v = int(s_v), int(o_v) if s_v == o_v: continue return s_v < o_v elif s_k: return True elif o_k: return False else: s_v, o_v = self.d(s_v), self.d(o_v) if s_v == o_v: continue return s_v < o_v return False def __eq__(self, other): if not isinstance(self, type(other)): return NotImplemented groups = map(lambda i: itertools.groupby(i, type(self).isdigit), (self, other)) zipped = itertools.zip_longest(*groups) for s,o in zipped: if s is None or o is None: return False s_k, s_v = s[0],"".join(s[1]) o_k, o_v = o[0],"".join(o[1]) if s_k and o_k: s_v, o_v = int(s_v), int(o_v) if s_v == o_v: continue return False elif s_k or o_k: return False else: s_v, o_v = self.d(s_v), self.d(o_v) if s_v == o_v: continue return False return True __le__ = object.__le__ __ne__ = object.__ne__ __gt__ = object.__gt__ __ge__ = object.__ge__ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | import functools import itertools import enum class OrderingType(enum.Enum): PerWordSwapCase = lambda s: s.lower()+s.swapcase() PerCharacterSwapCase = lambda s:"".join(c.lower()+c.swapcase() for c in s) class NaturalOrdering: @classmethod def by(cls, ordering): def wrapper(string): return cls(string, ordering) return wrapper def __init__(self, string, ordering=OrderingType.PerCharacterSwapCase): self.string = string self.groups = [ (k,int("".join(v))) if k else (k,ordering("".join(v))) for k,v in itertools.groupby(string, str.isdigit) ] def __repr__(self): return"{}({})".format\ ( type(self).__name__ , self.string ) def __lesser(self, other, default): if not isinstance(self, type(other)): return NotImplemented for s,o in itertools.zip_longest(self.groups, other.groups): if s is None: return True if o is None: return False s_k, s_v = s o_k, o_v = o if s_k and o_k: if s_v == o_v: continue return s_v < o_v elif s_k: return True elif o_k: return False else: if s_v == o_v: continue return s_v < o_v return default def __lt__(self, other): return self.__lesser(other, default=False) def __le__(self, other): return self.__lesser(other, default=True) def __eq__(self, other): if not isinstance(self, type(other)): return NotImplemented for s,o in itertools.zip_longest(self.groups, other.groups): if s is None or o is None: return False s_k, s_v = s o_k, o_v = o if s_k and o_k: if s_v == o_v: continue return False elif s_k or o_k: return False else: if s_v == o_v: continue return False return True # functools.total_ordering doesn't create single-call wrappers if both # __le__ and __lt__ exist, so do it manually. def __gt__(self, other): op_result = self.__le__(other) if op_result is NotImplemented: return op_result return not op_result def __ge__(self, other): op_result = self.__lt__(other) if op_result is NotImplemented: return op_result return not op_result # __ne__ is the only implied ordering relationship, it automatically # delegates to __eq__ |
1 2 3 4 5 6 7 8 9 10 11 12 13 | >>> import natsort >>> import timeit >>> l1 = ['Apple', 'corn', 'apPlE', 'arbour', 'Corn', 'Banana', 'apple', 'banana'] >>> l2 = list(map(str, range(30))) >>> l3 = ["{} {}".format(x,y) for x in l1 for y in l2] >>> print(timeit.timeit('sorted(l3+["0"], key=NaturalStringA)', number=10000, globals=globals())) 362.4729259099986 >>> print(timeit.timeit('sorted(l3+["0"], key=NaturalStringB)', number=10000, globals=globals())) 189.7340817489967 >>> print(timeit.timeit('sorted(l3+["0"], key=NaturalOrdering.by(OrderingType.PerCharacterSwapCase))', number=10000, globals=globals())) 69.34636392899847 >>> print(timeit.timeit('natsort.natsorted(l3+["0"], alg=natsort.ns.GROUPLETTERS | natsort.ns.LOWERCASEFIRST)', number=10000, globals=globals())) 98.2531585780016 |
自然排序既相当复杂,又模糊地定义为一个问题。不要忘记提前运行
我看到的所有算法都依赖于一些技巧,比如复制和降低字符,以及交换大小写。虽然这会使运行时间加倍,但另一种方法需要对输入字符集进行完全自然的排序。我不认为这是Unicode规范的一部分,因为Unicode数字比
上面的答案对于所展示的具体例子是很好的,但是对于更一般的自然类问题,遗漏了几个有用的例子。我刚从这些案例中得到一点教训,所以创造了一个更彻底的解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | def natural_sort_key(string_or_number): """ by Scott S. Lawton <[email protected]> 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的on和off)如下:http://productarchitect.com/code/better-natural-sort.py
欢迎反馈。这不是一个确定的解决方案,只是向前迈出了一步。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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中一次读取一个字母的字符串
我建议您使用
1 2 3 | to_order= [e2,E1,e5,E4,e3] ordered= sorted(to_order, key= lambda x: x.lower()) # ordered should be [E1,e2,e3,E4,e5] |
1 2 3 | >>> import re >>> sorted(lst, key=lambda x: int(re.findall(r'\d+$', x)[0])) ['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13'] |