如何在python中对字母数字集进行排序


72

我有一套

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

排序后,我希望它看起来像

4 sheets,
12 sheets,
48 sheets,
booklet

有什么想法吗

Answers:


60

简短而甜美:

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)

窒息,4a sheets但谁在乎呢?要解决此问题,您需要一个实函数而不是lambda。
让·弗朗索瓦·法布尔

这可能适用于这个简单的示例,但不适用于类似[“ 1. bla”,“ 2. blub”]的列表。拆分应该是正则表达式,然后再按第二部分进行排序,因此[“ 1 bcd”,“ 2 abc”,“ 1 xyz”]正确出现。
FrankyBoy

120

杰夫·阿特伍德(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之前)。


杰夫,您好,非常感谢。那正是我想要的。祝好运。
mmrs151 '04

2
是否可以基于元组中的第一个值来修改元组列表?范例: [('b', 0), ('0', 1), ('a', 2)]分类为[('0', 1), ('a', 2), ('b', 0)]
paragbaxi 2011年

3
此功能区分大小写。大写字符串优先。要解决此问题,请添加.lower()keyre.split
zamber 2015年

17

您应该查看第三方图书馆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

9

一种简单的方法是将字符串分为数字部分和非数字部分,并使用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)

5

有人建议我在这里重新发布此答案,因为它在这种情况下也很好用

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

通用答案,用于对字符串数组中任何位置的任何数字进行排序。适用于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']

答案的一部分来自那里


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']

0

集本质上是无序的。您需要创建一个具有相同内容的列表并对其进行排序。


4
不正确-内置的sorted()会采用任何顺序并返回已排序的列表。
PaulMcG 2010年

4
因此,与其创建列表并对其进行排序,不如使用内置函数来创建排序列表...。是的,我走了。
拉基斯

实现SortedSets(而不是HashSets)的集合本质上是有序的
axwell

0

对于那些使用2.4之前版本的Python却没有出色sorted()功能的人来说,一种快速排序集的方法是:

l = list(yourSet)
l.sort() 

这不能回答上面的特定问题(12 sheets将在之前出现4 sheets),但对来自Google的人可能有用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.