tuplas tabla para organizar ordenar orden lista funcion datos codigo cadena ascendentemente alfabetico python sorting python-3.x

tabla - organizar datos python



¿Python tiene una función incorporada para el ordenamiento natural de cadenas? (15)

Utilizando Python 3.x, tengo una lista de cadenas para las que me gustaría realizar una ordenación alfabética natural.

Ordenación natural: el orden por el cual se ordenan los archivos en Windows.

Por ejemplo, la siguiente lista está ordenada naturalmente (lo que quiero):

[''elm0'', ''elm1'', ''Elm2'', ''elm9'', ''elm10'', ''Elm11'', ''Elm12'', ''elm13'']

Y aquí está la versión "ordenada" de la lista anterior (lo que tengo):

[''Elm11'', ''Elm12'', ''Elm2'', ''elm0'', ''elm1'', ''elm10'', ''elm13'', ''elm9'']

Estoy buscando una función de ordenación que se comporte como la primera.


Valor de esta publicación

Mi punto es ofrecer una solución no regex que pueda aplicarse en general.
Voy a crear tres funciones:

  1. find_first_digit que tomé prestado de @AnuragUniyal . Encontrará la posición del primer o no dígito en una cadena.
  2. split_digits que es un generador que separa una cadena en trozos de dígitos y no dígitos. También yield números enteros cuando es un dígito.
  3. natural_key simplemente envuelve split_digits en una tuple . Esto es lo que usamos como clave para sorted , max , min .

Funciones

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))

Podemos ver que es general en que podemos tener fragmentos de varios dígitos:

# Note that the key has lower case letters natural_key(''asl;dkfDFKJ:sdlkfjdf809lkasdjfa_543_hh'') (''asl;dkfdfkj:sdlkfjdf'', 809, ''lkasdjfa_'', 543, ''_hh'')

O dejar como mayúsculas y minúsculas:

natural_key(''asl;dkfDFKJ:sdlkfjdf809lkasdjfa_543_hh'', True) (''asl;dkfDFKJ:sdlkfjdf'', 809, ''lkasdjfa_'', 543, ''_hh'')

Podemos ver que ordena la lista de OP en el orden apropiado

sorted( [''elm0'', ''elm1'', ''Elm2'', ''elm9'', ''elm10'', ''Elm11'', ''Elm12'', ''elm13''], key=natural_key ) [''elm0'', ''elm1'', ''Elm2'', ''elm9'', ''elm10'', ''Elm11'', ''Elm12'', ''elm13'']

Pero también puede manejar listas más complicadas:

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'']

Mi equivalente de expresiones regulares sería

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))


Aquí hay una versión mucho más pitónica de la respuesta de Mark Byer:

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)]

Ahora esta función se puede utilizar como una clave en cualquier función que la use, como list.sort , sorted , max , etc.

Como un lambda:

lambda s: [int(t) if t.isdigit() else t.lower() for t in re.split(''(/d+)'', s)]


Basándome en las respuestas aquí, escribí una función natural_sorted que se comporta como la función incorporada sorted :

# 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)

El código fuente también está disponible en mi repositorio de fragmentos de GitHub: https://github.com/bdrung/snippets/blob/master/natural_sorted.py


Dado:

data=[''Elm11'', ''Elm12'', ''Elm2'', ''elm0'', ''elm1'', ''elm10'', ''elm13'', ''elm9'']

Similar a la solución de SergO, un 1-liner sin bibliotecas externas sería :

data.sort(key=lambda x : int(x[3:]))

o

sorted_data=sorted(data, key=lambda x : int(x[3:]))

Explicación:

Esta solución utiliza la característica clave de clasificación para definir una función que se empleará para la clasificación. Como sabemos que cada entrada de datos está precedida por ''elm'', la función de clasificación se convierte en una parte entera de la cadena después del tercer carácter (es decir, int (x [3:])). Si la parte numérica de los datos está en una ubicación diferente, entonces esta parte de la función tendría que cambiar.

Aclamaciones


Escribí una función basada en http://www.codinghorror.com/blog/2007/12/sorting-for-humans-natural-sort-order.html que agrega la capacidad de pasar aún su propio parámetro ''clave''. Necesito esto para realizar un tipo natural de listas que contengan objetos más complejos (no solo cadenas).

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)

Por ejemplo:

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''}]


Hay una biblioteca de terceros para esto en PyPI llamada natsort (divulgación completa, soy el autor del paquete). Para su caso, puede hacer cualquiera de los siguientes:

>>> 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'']

Debe tener en cuenta que natsort utiliza un algoritmo general, por lo que debería funcionar para casi cualquier entrada que le natsort . Si desea obtener más detalles sobre por qué puede elegir una biblioteca para hacer esto en lugar de utilizar su propia función, consulte la natsort Cómo funciona de la documentación de natsort , en particular, ¡ Casos especiales en todas partes! sección.

Si necesita una clave de clasificación en lugar de una función de clasificación, utilice una de las fórmulas siguientes.

>>> 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'']


Las respuestas anteriores son buenas para el ejemplo específico que se mostró, pero faltan varios casos útiles para la pregunta más general de tipo natural. Acabo de ser mordido por uno de esos casos, así que creé una solución más completa:

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

El código de prueba y varios enlaces (dentro y fuera de ) están aquí: http://productarchitect.com/code/better-natural-sort.py

Comentarios bienvenidos. Eso no pretende ser una solución definitiva; Solo un paso adelante.


Le sugiero que simplemente use el argumento de la palabra key clave sorted para lograr la lista deseada
Por ejemplo:

to_order= [e2,E1,e5,E4,e3] ordered= sorted(to_order, key= lambda x: x.lower()) # ordered should be [E1,e2,e3,E4,e5]


Lo más probable es que functools.cmp_to_key() esté estrechamente vinculado a la implementación subyacente de la ordenación de python. Además, el parámetro cmp es legado. La forma moderna es transformar los elementos de entrada en objetos que admiten las ricas operaciones de comparación deseadas.

Bajo CPython 2.x, se pueden ordenar objetos de diferentes tipos incluso si no se han implementado los respectivos operadores de comparación ricos. Bajo CPython 3.x, los objetos de diferentes tipos deben admitir explícitamente la comparación. Ver ¿Cómo Python compara la cadena y el int? que enlaza a la documentación oficial . La mayoría de las respuestas dependen de este ordenamiento implícito. Cambiar a Python 3.x requerirá un nuevo tipo para implementar y unificar comparaciones entre números y cadenas.

Python 2.7.12 (default, Sep 29 2016, 13:30:34) >>> (0,"foo") < ("foo",0) True

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()

Hay tres enfoques diferentes. El primero utiliza clases anidadas para aprovechar el algoritmo de comparación de Iterable de Python. El segundo desenrolla este anidamiento en una sola clase. La tercera parte de subclasificación str centran en el rendimiento. Todos son cronometrados; el segundo es el doble de rápido y el tercero casi seis veces más rápido. La subclasificación no es obligatoria, y probablemente fue una mala idea en primer lugar, pero viene con ciertas conveniencias.

Los caracteres de clasificación se duplican para forzar el ordenamiento por caso, y se intercambian entre mayúsculas y minúsculas para forzar a la letra minúscula a ordenar primero; Esta es la definición típica de "género natural". No pude decidir sobre el tipo de agrupación; Algunos pueden preferir lo siguiente, lo que también trae importantes beneficios de rendimiento:

d = lambda s: s.lower()+s.swapcase()

Cuando se utilizan, los operadores de comparación se establecen en el de object para que no sean ignorados por functools.total_ordering .

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__

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__

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__

>>> 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

La clasificación natural es bastante complicada y vagamente definida como un problema. No olvide ejecutar unicodedata.normalize(...) antemano, y considere usar str.casefold() lugar de str.lower() . Probablemente hay problemas de codificación sutiles que no he considerado. Así que tentativamente recomiendo la biblioteca natsort . Eché un vistazo rápido al repositorio de github; El código de mantenimiento ha sido estelar.

Todos los algoritmos que he visto dependen de trucos como la duplicación y reducción de caracteres y el intercambio de mayúsculas y minúsculas. Si bien esto duplica el tiempo de ejecución, una alternativa requeriría un orden natural total en el conjunto de caracteres de entrada. No creo que esto sea parte de la especificación de Unicode, y dado que hay muchos más dígitos de Unicode que [0-9] , crear tal clasificación sería igualmente desalentador. Si desea comparaciones locale.strxfrm configuración regional, prepare sus cadenas con locale.strxfrm según la Clasificación de Python CÓMO .


Prueba esto:

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)

Salida:

[''elm0'', ''elm1'', ''Elm2'', ''elm9'', ''elm10'', ''Elm11'', ''Elm12'', ''elm13'']

ideone trabajando en línea: ideone .

Código adaptado de aquí: Clasificación para humanos: orden natural .


Una opción es convertir la cadena en una tupla y reemplazar los dígitos mediante el formulario expandido http://wiki.answers.com/Q/What_does_expanded_form_mean

de esa manera a90 se convertiría en ("a", 90,0) y a1 se convertiría en ("a", 1)

A continuación se muestra un código de ejemplo (que no es muy eficiente debido a la forma en que elimina los 0 iniciales de los números)

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)

salida:

(''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'']


>>> import re >>> sorted(lst, key=lambda x: int(re.findall(r''/d+$'', x)[0])) [''elm0'', ''elm1'', ''Elm2'', ''elm9'', ''elm10'', ''Elm11'', ''Elm12'', ''elm13'']


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

Agradecimientos :

Bubble Sort Homework

Cómo leer una cadena una letra a la vez en python


data = [''elm13'', ''elm9'', ''elm0'', ''elm1'', ''Elm11'', ''Elm2'', ''elm10'']

Analicemos los datos. La capacidad de dígitos de todos los elementos es 2. Y hay 3 letras en la parte literal ''elm'' .

Por lo tanto, la longitud máxima del elemento es 5. Podemos aumentar este valor para asegurarnos (por ejemplo, a 8).

Teniendo eso en cuenta, tenemos una solución de una línea:

data.sort(key=lambda x: ''{0:0>8}''.format(x).lower())

Sin expresiones regulares y bibliotecas externas!

print(data) >>> [''elm0'', ''elm1'', ''Elm2'', ''elm9'', ''elm10'', ''Elm11'', ''elm13'']

Explicación:

for elm in data: print(''{0:0>8}''.format(elm).lower()) >>> 0000elm0 0000elm1 0000elm2 0000elm9 000elm10 000elm11 000elm13


Y ahora para algo más * elegante (pythonic) - solo un toque

Hay muchas implementaciones por ahí, y aunque algunas se han acercado, ninguna ha capturado la elegancia que ofrece la pitón moderna.

  • Probado utilizando python (3.5.1)
  • Incluye una lista adicional para demostrar que funciona cuando los números están en la mitad de la cadena
  • No probé, sin embargo, asumo que si su lista fuera considerable, sería más eficiente compilar la expresión regular de antemano
    • Estoy seguro de que alguien me corregirá si se trata de una suposición errónea
Rápido

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)]) Código Completo

#!/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'']

Precaución al usar

  • from os.path import split
    • Necesitarás diferenciar las importaciones.

Inspiración de