web-dev-qa-db-fra.com

Comment trier les ensembles alphanumériques en python

J'ai un set 

set(['booklet', '4 sheets', '48 sheets', '12 sheets'])

Après le tri, je veux que ça ressemble à 

4 sheets,
12 sheets,
48 sheets,
booklet

Toute idée s'il vous plaît

58
mmrs151

Court et doux:

sorted(data, key=lambda item: (int(item.partition(' ')[0])
                               if item[0].isdigit() else float('inf'), item))

Cette version:

  • Fonctionne en Python 2 et Python 3, car:
    • Cela ne suppose pas que vous compariez des chaînes et des entiers (ce qui ne fonctionnera pas dans Python 3)
    • Il n'utilise pas le paramètre cmp à sorted (qui n'existe pas dans Python 3)
  • Triera sur la partie de chaîne si les quantités sont égales

Si vous voulez une sortie imprimée exactement comme décrit 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)
51
Daniel Stutzbach

Jeff Atwood parle de type naturel et donne un exemple d'une façon de le faire en Python. Voici ma variation à 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 ceci:

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

Un des avantages de cette méthode est qu’elle ne fonctionne pas uniquement lorsque les chaînes sont séparées par des espaces. Cela fonctionnera également pour d'autres séparateurs tels que la période dans les numéros de version (par exemple, 1.9.1 est antérieure à 1.10.0).

96
Mark Byers

Vous devriez vérifier la bibliothèque tierce partie natsort . Son algorithme est général donc il fonctionnera pour la plupart des entrées.

>>> import natsort
>>> your_list = set(['booklet', '4 sheets', '48 sheets', '12 sheets'])
>>> print ',\n'.join(natsort.natsorted(your_list))
4 sheets,
12 sheets,
48 sheets,
booklet
9
SethMMorton

Un moyen simple consiste à scinder les chaînes en parties numériques et en parties non numériques et à utiliser l'ordre de tri Tuple python pour trier les chaînes.

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)
7
Ants Aasma

Il a été suggéré que je republie cette réponse ici car cela 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émo:

>>> 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 aussi bien en Python2)

def keyfunc(s):
    return [int(''.join(g)) if k else ''.join(g) for k, g in groupby('\0'+s, str.isdigit)]
4
John La Rooy
>>> a = set(['booklet', '4 sheets', '48 sheets', '12 sheets'])
>>> def ke(s):
    i, sp, _ = s.partition(' ')
    if i.isnumeric():
        return int(i)
    return float('inf')

>>> sorted(a, key=ke)
['4 sheets', '12 sheets', '48 sheets', 'booklet']
2
SilentGhost

Basé sur la réponse de SilentGhost:

In [4]: a = set(['booklet', '4 sheets', '48 sheets', '12 sheets'])

In [5]: def f(x):
   ...:     num = x.split(None, 1)[0]
   ...:     if num.isdigit():
   ...:         return int(num)
   ...:     return x
   ...: 

In [6]: sorted(a, key=f)
Out[6]: ['4 sheets', '12 sheets', '48 sheets', 'booklet']
1
draebek

les ensembles sont intrinsèquement non commandés. Vous devrez créer une liste avec le même contenu et le trier. 

0
Rakis

Réponse générique pour trier tous les nombres à n’importe quelle position dans un tableau de chaînes. Fonctionne avec Python 2 & 3.

def alphaNumOrder(string):
   """ Returns all numbers on 5 digits to let sort the string with numeric order.
   Ex: alphaNumOrder("a6b12.125")  ==> "a00006b00012.00125"
   """
   return ''.join([format(int(x), '05d') if x.isdigit()
                   else x for x in re.split(r'(\d+)', string)])

Échantillon:

s = ['a10b20','a10b1','a3','b1b1','a06b03','a6b2','a6b2c10','a6b2c5']
s.sort(key=alphaNumOrder)
s ===> ['a3', 'a6b2', 'a6b2c5', 'a6b2c10', 'a06b03', 'a10b1', 'a10b20', 'b1b1']

Une partie de la réponse est à partir de là

0
Le Droid

Pour les personnes coincées avec une version de Python antérieure à la 2.4, sans la fonction sorted() merveilleuse, un moyen rapide de trier les ensembles est:

l = list(yourSet)
l.sort() 

Cela ne répond pas à la question spécifique ci-dessus (12 sheets viendra avant 4 sheets), mais cela pourrait être utile aux personnes venant de Google.

0
Giacomo Lacava