web-dev-qa-db-fra.com

Comment trier correctement une chaîne avec un nombre à l'intérieur?

Duplicate possible:
Est-ce que Python possède une fonction intégrée pour le tri naturel des chaînes?

J'ai une liste de chaînes contenant des nombres et je ne trouve pas un bon moyen de les trier.
Par exemple, je reçois quelque chose comme ceci:

something1
something12
something17
something2
something25
something29

avec la méthode sort().

Je sais que j'ai probablement besoin d'extraire les chiffres d'une manière ou d'une autre et ensuite de trier la liste, mais je ne sais pas comment le faire de la manière la plus simple.

93
Michal

Peut-être recherchez-vous tri humain (aussi appelé tri naturel ):

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(r'(\d+)', text) ]

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

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

les rendements

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

PS J'ai changé ma réponse pour utiliser la mise en œuvre du tri naturel de Toothy (posté dans les commentaires ici ) car il est nettement plus rapide que ma réponse d'origine.


Si vous souhaitez trier le texte avec des flottants, vous devez changer la regex de celle qui correspond à ints (i.e. (\d+)) à ne expression rationnelle qui correspond à float :

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)

les rendements

['something1', 'something1.0', 'something1.105', 'something1.25', 'something2']
187
unutbu