2010-04-19 2 views

ответ

43

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

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) 
+1

Отличный ответ Даниил – mmrs151

1
>>> 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

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

+2

Не верно - отсортированный() встроенный примет любую последовательность и возвращает отсортированный список , – PaulMcG

+3

Итак, вместо того, чтобы создавать список и сортировать его, вместо этого вы используете встроенный файл, чтобы создать отсортированный список. Да, я был далеко. – Rakis

1

На основании ответа 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'] 
83

Jeff Atwood говорит о естественном роде и дает пример одного из способов сделать это в 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).

+0

Hi Jeff, спасибо. Это именно то, что я искал. Удачи. – mmrs151

+2

Можно ли изменить это для списка кортежей на основе первого значения в кортеже?Пример: '[('b', 0), ('0', 1), ('a', 2)]' сортируется в '[('0', 1), ('a', 2), ('b', 0)] ' – paragbaxi

+3

Эта функция чувствительна к регистру. Верхние строки будут иметь приоритет. Чтобы исправить это, добавьте '.lower()' в 'key' в' re.split'. – zamber

6

Простым способом является разделение строк на числовые части и нечисловые части и использование порядка сортировки кортежей 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) 
3

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

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)] 
1

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

l = list(yourSet) 
l.sort() 

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

4

Вы должны проверить стороннюю библиотеку 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 
0

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

Часть ответа is from there