简体   繁体   中英

Sort list of objects by attribute alphanumerically

I have a list of objects of the same type

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

that I wish to sort naturally by the object attribute name . I have tried

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

However this sorts the list as

A1
A10
A2

Not in the format that I wanted

A1
A2
A10

I have tried modifying the code from sorting alphanumeric strings , but I can't get it working for a list of objects.

This way uses groupby, and works for an arbitrary number of swaps between alpha and digits

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)

Demo:

>>> 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']
sorted(obj, key=lambda x: (x.name[0], int(x.name[1:])))

Something like this:

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)

Demo:

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

A slightly modified version of sorted_nicely that can work for your object:

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)

This answers the OP question how to sort the list of objects "naturally" by a property:

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

I was able to find a solutions based on beauburriers solution to natural sorting

Modified to remove the custom key option

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM