【问题标题】:Sort list of objects by attribute alphanumerically按属性按字母数字对对象列表进行排序
【发布时间】:2013-06-14 16:45:51
【问题描述】:

我有一个相同类型的对象列表

lis = [<obj>, <obj>, <obj>]

我希望按对象属性name 自然排序。我试过了

sortedlist = sorted(lis, key=lambda x: x.name)

但是这会将列表排序为

A1
A10
A2

不是我想要的格式

A1
A2
A10

我已尝试修改 sorting alphanumeric strings 中的代码,但无法使其适用于对象列表。

【问题讨论】:

  • 这称为“自然”排序,参见stackoverflow.com/q/11150239/989121 和其中的链接示例。
  • 感谢所有的建议,但它们都是为了对一个简单的列表进行排序。不是对象列表。我希望排序的是使用自然排序的对象属性名称的`List = [, , ]

标签: python sorting


【解决方案1】:

这种方式使用 groupby,并且适用于 alpha 和数字之间的任意数量的交换

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_list =['A1', 'A10', 'A2', 'B0', 'AA11', 'AB10']
>>> sorted(my_list, key=keyfunc)
['A1', 'A2', 'A10', 'AA11', 'AB10', 'B0']

>>> mylist =['foo1', 'foo10', 'foo2', 'foo2bar1', 'foo2bar10', 'foo2bar3']
>>> sorted(mylist, key=keyfunc)
['foo1', 'foo2', 'foo2bar1', 'foo2bar3', 'foo2bar10', 'foo10']

【讨论】:

  • +1 不错的解决方案,您也应该将其发布在 thread 上。
  • 感谢您发布此内容,提供的其他解决方案均不适合我。
【解决方案2】:
sorted(obj, key=lambda x: (x.name[0], int(x.name[1:])))

【讨论】:

  • 这适用于单个字母后跟一些数字的非常有限的情况:p
  • 这可能适用于我的情况,因为命名遵循特定格式
  • @Scavenger 我基于你的具体情况,因为这就是问题所在,如果我的数据总是一种特定格式,我也会使用这个
【解决方案3】:

类似这样的:

import re
def func(x):
   foo = re.search(r'([A-Z]+)(\d+)',x.name)
   return foo.group(1), int(foo.group(2))
print sorted(obj, key = func)

演示:

lis =['A1', 'A10', 'A2', 'B0', 'AA11', 'AB10']
def func(x):
   foo = re.search(r'([A-Z]+)(\d+)',x)
   return foo.group(1), int(foo.group(2))
print sorted(lis, key = func)
#['A1', 'A2', 'A10', 'AA11', 'AB10', 'B0']

sorted_nicely 的略微修改版本,可用于您的对象:

def sorted_nicely( x ): 
    """ Sort the given iterable in the way that humans expect.""" 
    convert = lambda text: int(text) if text.isdigit() else text 
    return [ convert(c) for c in re.split('([0-9]+)', x.name) ]

obj.sort(key = sorted_nicely)
#or sorted(obj, key = sorted_nicely)

【讨论】:

  • 你的正则表达式是错误的,因为\w+ 是贪婪的并且匹配数字。你的\d+ 只会匹配最后一个数字,因为其余的将被吸进第一组。
【解决方案4】:

我能够找到基于beauburrierssolution to natural sorting的解决方案

修改为移除自定义键选项

import re

def natural_sort(lis):
    """
    Sort the list into natural alphanumeric order.
    """
    def get_alphanum_key_func(key):
       convert = lambda text: int(text) if text.isdigit() else text 
       return lambda s: [convert(c) for c in re.split('([0-9]+)', key(s))]
    sort_key = get_alphanum_key_func(lambda x: x.name)
    lis.sort(key=sort_key)

【讨论】:

    【解决方案5】:

    这回答了 OP 问题如何按属性“自然地”对对象列表进行排序:

    import re
    
    def natkey(s):
        return [w or int(n) for w, n in re.findall('(\D+)|(\d+)', s)]
    
    class X:
        def __init__(self, name):
            self.name = name
    
    lst = [X('AB1'), X('AB10'), X('AB2'), X('AB12')]
    lst.sort(key=lambda obj: natkey(obj.name))
    print [obj.name for obj in lst]
    # ['AB1', 'AB2', 'AB10', 'AB12']
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多