compara dos cadenas de python que contienen números

ACTUALIZACIÓN: Debería haber especificado esto antes, pero no todos los nombres son simplemente flotantes. Por ejemplo, algunos de ellos están “prefijados” con “YT”. Entonces, por ejemplo, “YT1.1. Entonces, tienes el mismo problema YT1.9 <YT1.11 debería ser cierto. Estoy realmente sorprendido de que la comparación de cadenas falle …

hola, esta debería ser una pregunta bastante simple pero parece que no puedo encontrar la respuesta. Me gustaría ordenar un montón de hojas de trabajo XL por nombre. Cada uno de los nombres son números, pero de la misma manera que las “secciones” de los libros de texto están numeradas, lo que significa que la sección 4.11 viene después de 4.10 y ambas aparecen después de 4.9 y 4.1. Pensé que simplemente comparar estos números como lo haría una cadena pero obtengo lo siguiente:

>>> s1 = '4.11' >>> s2 = '4.2' >>> s1> s2 False >>> n1 = 4.11 >>> n2 = 4.2 >>> n1 > n2 False 

¿Cómo puedo comparar estos dos valores de modo que 4.11 sea mayor que 4.2?

Convierta los nombres a tuplas de enteros y compare las tuplas:

 def splittedname(s): return tuple(int(x) for x in s.split('.')) splittedname(s1) > splittedname(s2) 

Actualización : dado que, aparentemente, sus nombres pueden contener otros caracteres que no sean dígitos, deberá verificar el valor de ValueError y dejar los valores que no se pueden convertir a ints sin cambios:

 import re def tryint(x): try: return int(x) except ValueError: return x def splittedname(s): return tuple(tryint(x) for x in re.split('([0-9]+)', s)) 

Para ordenar una lista de nombres, use splittedname como una función clave para sorted :

 >>> names = ['YT4.11', '4.3', 'YT4.2', '4.10', 'PT2.19', 'PT2.9'] >>> sorted(names, key=splittedname) ['4.3', '4.10', 'PT2.9', 'PT2.19', 'YT4.2', 'YT4.11'] 

Este no es un método incorporado, pero debería funcionar:

 >>> def lt(num1, num2): ... for a, b in zip(num1.split('.'), num2.split('.')): ... if int(a) < int(b): ... return True ... if int(a) > int(b): ... return False ... return False ... ... lt('4.2', '4.11') 0: True 

Eso se puede limpiar, pero te da la esencia.

Lo que buscas se llama “clasificación natural”. Eso se opone a la “clasificación lexicográfica”. Hay varias recetas por ahí que hacen esto, ya que el resultado exacto de lo que desea es específico de la implementación. Una búsqueda rápida en Google produce esto (nota * este no es mi código, ni lo he probado):

 import re def tryint(s): try: return int(s) except: return s def alphanum_key(s): """ Turn a string into a list of string and number chunks. "z23a" -> ["z", 23, "a"] """ return [ tryint(c) for c in re.split('([0-9]+)', s) ] def sort_nicely(l): """ Sort the given list in the way that humans expect. """ l.sort(key=alphanum_key) 

http://nedbatchelder.com/blog/200712.html#e20071211T054956

use s1.split(".") para crear una lista de los elementos antes y después del decimal, luego ordene la lista de listas, por ejemplo:

 import random sheets = list([str(x), str(y)] for x in xrange(1, 5) for y in xrange(0,99)) print sheets #sheets in order random.shuffle(sheets) print sheets #sheets out of order sheets.sort() print sheets #sheets back in order 

Por lo tanto, su implementación podría ser:

 #assume input sheets is a list of the worksheet names sheets = list(x.split(".") for x in input_sheets) sheets.sort() 

Si sabes que son números reales [*], simplemente:

 >>> float(s1) > float(s2) True 

[*] De lo contrario, prepárate para manejar un ValueError elevado.