pythonsortingsecondary-sort

Sort strings in Python list using another list


Say I have the following lists:

List1=['Name1','Name3','Color1','Size2','Color3','Color2','Name2','Size1', 'ID']
List2=['ID','Color1','Color2','Size1','Size2','Name1','Name2']

Each list will have element named "ID" variable and then 3 other categories (Name, Color, and Size) of which there is an unpredetermined number of elements in each category.

I want to sort these variables without knowing how many there will be in each category with the following 'sort list':

SortList=['ID','Name','Size','Color']

I can get the desired output (see below) although I imagine there is a better / more pythonic way of doing so.

>>> def SortMyList(MyList,SortList):       
...     SortedList=[]       
...     for SortItem in SortList:
...         SortItemList=[]
...         for Item in MyList:
...             ItemWithoutNum="".join([char for char in Item if char.isalpha()])  
...             if SortItem==ItemWithoutNum:
...                 SortItemList.append(Item)
...         if len(SortItemList)>1:
...             SortItemList=[SortItem+str(I) for I in range(1,len(SortItemList)+1)]
...         for SortedItem in SortItemList:
...             SortedList.append(SortedItem)
...     return SortedList
... 
>>> 
>>> SortMyList(List1, SortList)
['ID', 'Name1', 'Name2', 'Name3', 'Size1', 'Size2', 'Color1', 'Color2', 'Color3']
>>> SortMyList(List2, SortList)
['ID', 'Name1', 'Name2', 'Size1', 'Size2', 'Color1', 'Color2']
>>> 

Any suggestions as to how my methodology or my code can be improved?


Solution

  • You can sort the list using a custom key function, which returns a 2-tuple, for primary sorting and secondary sorting.

    Primary sorting is by the order of your "tags" (ID first, then Name, etc.). Secondary sorting is by the numeric value following it.

    tags = ['ID','Name','Size','Color']
    sort_order = { tag : i for i,tag in enumerate(tags) }
    
    def elem_key(x):
        for tag in tags:
            if x.startswith(tag):
                suffix = x[len(tag) : ]
                return ( sort_order[tag],
                         int(suffix) if suffix else None )
        raise ValueError("element %s is not prefixed by a known tag. order is not defined" % x)
    
    list1.sort(key = elem_key)