2011-05-11 14 views
58

Duplicar posible:
Does Python have a built in function for string natural sort?¿Cómo ordenar correctamente una cadena con un número dentro?

que tiene una lista de cadenas que contienen los números y no puedo encontrar una buena manera de clasificarlos.
Por ejemplo me sale algo como esto:

something1 
something12 
something17 
something2 
something25 
something29 

con el método sort().

Sé que probablemente necesite extraer los números de alguna manera y luego ordenar la lista, pero no tengo ni idea de cómo hacerlo de la manera más simple.

+0

¿cuál es el problema con sort()? – tMC

+5

Esto tiene un nombre, Natural Sort. Ver http://stackoverflow.com/questions/2545532/python-analog-of-natsort-function-sort-a-list-using-a-natural-order-algorithm y http://stackoverflow.com/questions/4836710/does-python-have-a-built-in-function-for-string-natural-sort y probablemente otros. –

+0

No sabía que tiene un nombre, mi mal. Gracias. – Michal

Respuesta

117

Tal vez están buscando human sorting (también conocido como natural sorting):

import re 

def atoi(text): 
    return int(text) if text.isdigit() else text 

def natural_keys(text): 
    ''' 
    alist.sort(key=natural_keys) sorts in human order 
    http://nedbatchelder.com/blog/200712/human_sorting.html 
    (See Toothy's implementation in the comments) 
    ''' 
    return [ atoi(c) for c in re.split('(\d+)', text) ] 

alist=[ 
    "something1", 
    "something12", 
    "something17", 
    "something2", 
    "something25", 
    "something29"] 

alist.sort(key=natural_keys) 
print(alist) 

produce

['something1', 'something2', 'something12', 'something17', 'something25', 'something29'] 

PS. He cambiado mi respuesta para usar la implementación de Toothy de clasificación natural (publicada en los comentarios here) ya que es significativamente más rápido que mi respuesta original.


Si desea ordenar el texto con flotadores, entonces tendrá que cambiar la expresión regular de uno que coincida con enteros (es decir (\d+)) a a regex that matches floats:

import re 

def atof(text): 
    try: 
     retval = float(text) 
    except ValueError: 
     retval = text 
    return retval 

def natural_keys(text): 
    ''' 
    alist.sort(key=natural_keys) sorts in human order 
    http://nedbatchelder.com/blog/200712/human_sorting.html 
    (See Toothy's implementation in the comments) 
    float regex comes from https://stackoverflow.com/a/12643073/190597 
    ''' 
    return [ atof(c) for c in re.split(r'[+-]?([0-9]+(?:[.][0-9]*)?|[.][0-9]+)', text) ] 

alist=[ 
    "something1", 
    "something2", 
    "something1.0", 
    "something1.25", 
    "something1.105"] 

alist.sort(key=natural_keys) 
print(alist) 

produce

['something1', 'something1.0', 'something1.105', 'something1.25', 'something2'] 
+0

Pude ordenar una lista de objetos que tenían una propiedad secundaria (cadena) usando lo anterior también. Simplemente reemplace "text" con "someobject", y luego "return [atoi (c) for c in re.split ('(\ d +)', someobject.someproperty)]'. – Jonny

+0

¿Sabes cómo extender esto al caso donde los números son flotantes? Por ejemplo, something1.0, something 1.25, something2.0. – painfulenglish

+1

@painfulenglish: modifiqué la publicación anterior para mostrar cómo ordenar texto de forma natural con flotadores. – unutbu

Cuestiones relacionadas