Как отсортировать буквенно-цифровой набор в Python - PullRequest
60 голосов
/ 19 апреля 2010

У меня есть набор

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

После сортировки хочу чтобы это выглядело как

4 sheets,
12 sheets,
48 sheets,
booklet

Любая идея, пожалуйста

Ответы [ 10 ]

99 голосов
/ 19 апреля 2010

Джефф Этвуд говорит о естественной сортировке и приводит пример одного из способов сделать это в Python. Вот мой вариант:

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)

Используйте вот так:

s = set(['booklet', '4 sheets', '48 sheets', '12 sheets'])
for x in sorted_nicely(s):
    print(x)

Выход:

4 sheets
12 sheets
48 sheets
booklet

Одним из преимуществ этого метода является то, что он не работает, только когда строки разделены пробелами. Он также будет работать для других разделителей, таких как период в номерах версий (например, 1.9.1 предшествует 1.10.0).

54 голосов
/ 19 апреля 2010

Коротко и сладко:

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

Эта версия:

  • Работает в Python 2 и Python 3, потому что:
    • Он не предполагает, что вы сравниваете строки и целые числа (что не работает в Python 3)
    • Он не использует параметр cmp для sorted (которого нет в Python 3)
  • Сортирует по части строки, если величины равны

Если вы хотите печатать вывод точно так, как описано в вашем примере, тогда:

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)
11 голосов
/ 18 июля 2014

Вам следует проверить стороннюю библиотеку natsort . Его алгоритм является общим, поэтому он будет работать для большинства входных данных.

>>> 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
7 голосов
/ 19 апреля 2010

Простой способ - разделить строки на числовые и нечисловые части и использовать порядок сортировки кортежей python для сортировки строк.

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)
4 голосов
/ 06 июня 2013

Было предложено, чтобы я репостил этот ответ здесь, так как он хорошо работает и для этого случая

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)

Демо-версия:

>>> my_set = {'booklet', '4 sheets', '48 sheets', '12 sheets'}
>>> sorted(my_set, key=keyfunc)
['4 sheets', '12 sheets', '48 sheets', 'booklet']

Для Python3 необходимо немного изменить его (эта версия работает нормально и в Python2)

def keyfunc(s):
    return [int(''.join(g)) if k else ''.join(g) for k, g in groupby('\0'+s, str.isdigit)]
2 голосов
/ 19 апреля 2010
>>> 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']
1 голос
/ 19 апреля 2010

На основании ответа 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']
0 голосов
/ 06 октября 2016

Общий ответ для сортировки любых чисел в любой позиции в массиве строк. Работает с 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)])

Пример:

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

Часть ответа оттуда

0 голосов
/ 22 октября 2013

Для людей, увлеченных версией Python до 2.4, без замечательной функции sorted(), быстрый способ сортировки наборов:

l = list(yourSet)
l.sort() 

Это не отвечает на конкретный вопрос выше (12 sheets придет раньше 4 sheets), но может быть полезно для людей, приходящих из Google.

0 голосов
/ 19 апреля 2010

наборов изначально неупорядочены. Вам нужно будет создать список с тем же содержанием и отсортировать его.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...