En utilisant Python 3.x, j'ai une liste de chaînes pour lesquelles je voudrais effectuer un tri alphabétique naturel.
Tri naturel: ordre de tri des fichiers dans Windows.
Par exemple, la liste suivante est naturellement triée (ce que je veux):
['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13']
Et voici la version "triée" de la liste ci-dessus (ce que j'ai):
['Elm11', 'Elm12', 'Elm2', 'elm0', 'elm1', 'elm10', 'elm13', 'elm9']
Je recherche une fonction de tri qui se comporte comme la première.
python
sorting
python-3.x
snakile
la source
la source
!1, 1, !a, a
. La seule façon d'obtenir un tri comme Windows semble être d'utiliser laStrCmpLogicalW
fonction Windows elle-même, car personne ne semble avoir correctement réimplémenté cette fonction (la source serait appréciée). Solution: stackoverflow.com/a/48030307/2441026Réponses:
Il existe une bibliothèque tierce pour cela sur PyPI appelée natsort (divulgation complète, je suis l'auteur du package). Pour votre cas, vous pouvez effectuer l'une des opérations suivantes:
Vous devez noter qu'il
natsort
utilise un algorithme général, il devrait donc fonctionner pour à peu près toutes les entrées que vous lui lancez. Si vous souhaitez plus de détails sur les raisons pour lesquelles vous pouvez choisir une bibliothèque pour ce faire plutôt que de lancer votre propre fonction, consultez la page Comment ça marche de lanatsort
documentation , en particulier les cas spéciaux partout! section.Si vous avez besoin d'une clé de tri au lieu d'une fonction de tri, utilisez l'une des formules ci-dessous.
la source
natsort
gère également «naturellement» le cas de plusieurs nombres séparés dans les chaînes. Super truc!Essaye ça:
Production:
Code adapté d'ici: Tri pour les humains: Ordre de tri naturel .
la source
return sorted(l, key)
au lieu del.sort(key)
? Est-ce pour un gain de performance ou simplement pour être plus pythonique?re.split('([0-9]+)', '0foo')
revient['', '0', 'foo']
. Pour cette raison, les chaînes seront toujours sur les index pairs et les entiers sur les index impairs dans le tableau.Voici une version beaucoup plus pythonique de la réponse de Mark Byer:
Maintenant , cette fonction peut être utilisée comme une clé dans une fonction qui l' utilise, comme
list.sort
,sorted
,max
, etc.En tant que lambda:
la source
J'ai écrit une fonction basée sur http://www.codinghorror.com/blog/2007/12/sorting-for-humans-natural-sort-order.html qui ajoute la possibilité de toujours passer votre propre paramètre «clé». J'en ai besoin pour effectuer une sorte naturelle de listes qui contiennent des objets plus complexes (pas seulement des chaînes).
Par exemple:
la source
natural_sort_key
, puis lors du tri d'une liste, vous pourriez faire la chaîne de vos clés, par exemple:list.sort(key=lambda el: natural_sort_key(el['name']))
Analysons les données. La capacité numérique de tous les éléments est de 2. Et il y a 3 lettres dans la partie littérale commune
'elm'
.Ainsi, la longueur maximale de l'élément est 5. Nous pouvons augmenter cette valeur pour nous en assurer (par exemple, à 8).
Gardant cela à l'esprit, nous avons une solution en ligne:
sans expressions régulières et bibliothèques externes!
Explication:
la source
width = max(data, key=len)
pour calculer quoi sous8
'{0:0>{width}}'.format(x, width=width)
Donné:
Semblable à la solution de SergO, un liner sans bibliothèques externes serait :
ou
Explication:
Cette solution utilise la fonctionnalité clé de tri pour définir une fonction qui sera utilisée pour le tri. Parce que nous savons que chaque entrée de données est précédée de «elm», la fonction de tri convertit en entier la partie de la chaîne après le 3ème caractère (c'est-à-dire int (x [3:])). Si la partie numérique des données se trouve à un emplacement différent, alors cette partie de la fonction devrait changer.
À votre santé
la source
Il existe de nombreuses implémentations, et bien que certaines se soient rapprochées, aucune n'a capturé l'élégance offerte par le python moderne.
Attention lors de l'utilisation
from os.path import split
Inspiration de
la source
Valeur de ce message
Mon point est d'offrir une solution non regex qui peut être appliquée de manière générale.
Je vais créer trois fonctions:
find_first_digit
que j'ai emprunté à @AnuragUniyal . Il trouvera la position du premier chiffre ou non numérique dans une chaîne.split_digits
qui est un générateur qui sélectionne une chaîne en morceaux numériques et non numériques. Il sera égalementyield
entier lorsqu'il s'agit d'un chiffre.natural_key
s'enroule justesplit_digits
dans untuple
. C'est ce que nous utilisons comme clé poursorted
,max
,min
.Les fonctions
Nous pouvons voir qu'il est général en ce sens que nous pouvons avoir des morceaux à plusieurs chiffres:
Ou laissez en respectant la casse:
Nous pouvons voir qu'il trie la liste des PO dans l'ordre approprié
Mais il peut également gérer des listes plus compliquées:
Mon équivalent regex serait
la source
Une option consiste à transformer la chaîne en un tuple et à remplacer les chiffres à l'aide du formulaire étendu http://wiki.answers.com/Q/What_does_expanded_form_mean
de cette façon, a90 deviendrait ("a", 90,0) et a1 deviendrait ("a", 1)
ci-dessous est un exemple de code (qui n'est pas très efficace en raison de la façon dont il supprime les 0 en tête des nombres)
production:
la source
('b', 1) < ('b', 'e', 't', 'a', 1, '.', 1)
reviendraTypeError: unorderable types: int() < str()
natsort
, pypi.org/project/natsortSur la base des réponses ici, j'ai écrit une
natural_sorted
fonction qui se comporte comme la fonction intégréesorted
:Le code source est également disponible dans mon référentiel d'extraits de GitHub: https://github.com/bdrung/snippets/blob/master/natural_sorted.py
la source
Les réponses ci-dessus sont bonnes pour l' exemple spécifique qui a été montré, mais manquent plusieurs cas utiles pour la question plus générale du type naturel. Je viens de mordre par l'un de ces cas, j'ai donc créé une solution plus approfondie:
Le code de test et plusieurs liens (sur et hors de StackOverflow) sont ici: http://productarchitect.com/code/better-natural-sort.py
Commentaires bienvenus. Ce n'est pas censé être une solution définitive; juste un pas en avant.
la source
natsorted
ethumansorted
échouez parce qu'ils ont été mal utilisés ... vous avez essayé de passernatsorted
comme clé mais c'est en fait la fonction de tri elle-même. Vous auriez dû essayernatsort_keygen()
.Le plus probable
functools.cmp_to_key()
est étroitement lié à l'implémentation sous-jacente du tri de python. De plus, le paramètre cmp est hérité. La méthode moderne consiste à transformer les éléments d'entrée en objets qui prennent en charge les opérations de comparaison riches souhaitées.Sous CPython 2.x, des objets de types disparates peuvent être ordonnés même si les opérateurs de comparaison riche respectifs n'ont pas été implémentés. Sous CPython 3.x, les objets de différents types doivent explicitement prendre en charge la comparaison. Voir Comment Python compare-t-il string et int? qui renvoie à la documentation officielle . La plupart des réponses dépendent de cet ordre implicite. Le passage à Python 3.x nécessitera un nouveau type pour implémenter et unifier les comparaisons entre les nombres et les chaînes.
Il existe trois approches différentes. Le premier utilise des classes imbriquées pour tirer parti de l'
Iterable
algorithme de comparaison de Python . La seconde déroule cette imbrication en une seule classe. Le troisième renonce au sous-classementstr
pour se concentrer sur la performance. Tous sont chronométrés; le second est deux fois plus rapide tandis que le troisième presque six fois plus rapide. Le sousstr
- classement n'est pas requis, et c'était probablement une mauvaise idée en premier lieu, mais cela vient avec certaines commodités.Les caractères de tri sont dupliqués pour forcer le tri par casse et permutés pour forcer la lettre minuscule à trier en premier; c'est la définition typique du "tri naturel". Je ne pouvais pas décider du type de regroupement; certains pourraient préférer ce qui suit, ce qui apporte également des avantages de performances significatifs:
Lorsqu'ils sont utilisés, les opérateurs de comparaison sont définis sur celui de
object
sorte qu'ils ne seront pas ignorés parfunctools.total_ordering
.Le tri naturel est à la fois assez compliqué et vaguement défini comme un problème. N'oubliez pas de courir
unicodedata.normalize(...)
avant et pensez à utiliserstr.casefold()
plutôt qu'àstr.lower()
. Il y a probablement des problèmes d'encodage subtils que je n'ai pas pris en compte. Je recommande donc provisoirement la bibliothèque natsort . J'ai jeté un rapide coup d'œil au dépôt github; la maintenance du code a été stellaire.Tous les algorithmes que j'ai vus dépendent d'astuces telles que la duplication et la réduction de caractères et l'échange de casse. Bien que cela double le temps d'exécution, une alternative nécessiterait un ordre naturel total sur le jeu de caractères d'entrée. Je ne pense pas que cela fasse partie de la spécification unicode, et comme il y a beaucoup plus de chiffres unicode que
[0-9]
, créer un tel tri serait tout aussi intimidant. Si vous voulez des comparaisons locales, préparez vos chaînes aveclocale.strxfrm
le tri de Python COMMENT FAIRE .la source
Permettez-moi de soumettre ma propre opinion sur ce besoin:
Maintenant, si nous avons la liste comme telle:
Nous pouvons simplement utiliser le
key=
kwarg pour faire un tri naturel:L'inconvénient ici est bien sûr, comme c'est le cas actuellement, la fonction triera les lettres majuscules avant les lettres minuscules.
Je laisse au lecteur l'implémentation d'un mérou insensible à la casse :-)
la source
Je vous suggère simplement d'utiliser l'
key
argument mot clé desorted
pour obtenir la liste souhaitée.Par exemple:
la source
a_51
serait aprèsa500
, bien que 500> 51Suite à la réponse de @Mark Byers, voici une adaptation qui accepte le
key
paramètre, et est plus conforme au PEP8.J'ai aussi fait un Gist
la source
key
paramètre? Mais cela est également illustré dans la réponse de @ beauburrierUne amélioration par rapport à l'amélioration de Claudiu par rapport à la réponse de Mark Byer ;-)
BTW, peut-être que tout le monde ne se souvient pas que les valeurs par défaut des arguments de fonction sont évaluées au
def
momentla source
Remerciements :
Bubble Sort Devoirs
Comment lire une chaîne une lettre à la fois en python
la source
la source