J'ai un ensemble
set(['booklet', '4 sheets', '48 sheets', '12 sheets'])
Après le tri, je veux que cela ressemble à
4 sheets,
12 sheets,
48 sheets,
booklet
Une idée, s'il vous plaît
J'ai un ensemble
set(['booklet', '4 sheets', '48 sheets', '12 sheets'])
Après le tri, je veux que cela ressemble à
4 sheets,
12 sheets,
48 sheets,
booklet
Une idée, s'il vous plaît
Jeff Atwood parle du tri naturel et donne un exemple d'une façon de le faire en Python. Voici ma variation sur ce sujet :
import re
def sorted_nicely( l ):
""" Sort the given iterable in the way that humans expect."""
convert = lambda text: int(text) if text.isdigit() else text
alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ]
return sorted(l, key = alphanum_key)
Utilisez comme ça :
s = set(['booklet', '4 sheets', '48 sheets', '12 sheets'])
for x in sorted_nicely(s):
print(x)
Sortie :
4 sheets
12 sheets
48 sheets
booklet
L'un des avantages de cette méthode est qu'elle ne fonctionne pas uniquement lorsque les chaînes de caractères sont séparées par des espaces. Elle fonctionne également pour d'autres séparateurs tels que le point dans les numéros de version (par exemple 1.9.1 vient avant 1.10.0).
Est-il possible de modifier cela pour une liste de tuples basée sur la première valeur du tuple ? Exemple : [('b', 0), ('0', 1), ('a', 2)]
est trié en [('0', 1), ('a', 2), ('b', 0)]
Cette fonction est sensible à la casse. Les chaînes de caractères en majuscules sont prioritaires. Pour corriger cela, ajoutez .lower()
a key
sur re.split
.
Court et doux :
sorted(data, key=lambda item: (int(item.partition(' ')[0])
if item[0].isdigit() else float('inf'), item))
Cette version :
cmp
pour sorted
(qui n'existe pas dans Python 3)Si vous voulez que la sortie imprimée soit exactement comme décrite dans votre exemple, alors :
data = set(['booklet', '4 sheets', '48 sheets', '12 sheets'])
r = sorted(data, key=lambda item: (int(item.partition(' ')[0])
if item[0].isdigit() else float('inf'), item))
print ',\n'.join(r)
S'étrangle 4a sheets
mais qui s'en soucie ? pour résoudre ce problème, il faudrait une vraie fonction au lieu d'une lambda.
Cela pourrait fonctionner pour cet exemple trivial mais pas pour une liste comme ["1. bla", "2. blub"]. La séparation devrait probablement être une regex à la place, et aussi trier par la deuxième partie après, de sorte que ["1 bcd", "2 abc", "1 xyz"] sorte correctement.
Une méthode simple consiste à diviser les chaînes de caractères en parties numériques et non numériques et à utiliser l'ordre de tri des tuplets de Python pour trier les chaînes de caractères.
import re
tokenize = re.compile(r'(\d+)|(\D+)').findall
def natural_sortkey(string):
return tuple(int(num) if num else alpha for num, alpha in tokenize(string))
sorted(my_set, key=natural_sortkey)
Il m'a été suggéré de reposter cette réponse ici, car il fonctionne bien pour ce cas aussi.
from itertools import groupby
def keyfunc(s):
return [int(''.join(g)) if k else ''.join(g) for k, g in groupby(s, str.isdigit)]
sorted(my_list, key=keyfunc)
Démonstration :
>>> my_set = {'booklet', '4 sheets', '48 sheets', '12 sheets'}
>>> sorted(my_set, key=keyfunc)
['4 sheets', '12 sheets', '48 sheets', 'booklet']
Pour Python3, il est nécessaire de le modifier légèrement (cette version fonctionne également avec Python2).
def keyfunc(s):
return [int(''.join(g)) if k else ''.join(g) for k, g in groupby('\0'+s, str.isdigit)]
Pour les personnes coincées avec une version de Python antérieure à la version 2.4, sans la merveilleuse fonction sorted()
un moyen rapide de trier les ensembles :
l = list(yourSet)
l.sort()
Cela ne répond pas à la question spécifique ci-dessus ( 12 sheets
viendra avant 4 sheets
), mais il pourrait être utile aux personnes venant de Google.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.