Search code examples
pythonsortingnatural-sort

Sorting list of tuple in Python


I have the following list of tuples already sorted, with "sorted" in python:

L = [("1","blaabal"),
     ("1.2","bbalab"),
     ("10","ejej"),
     ("11.1","aaua"),
     ("12.1","ehjej"),
     ("12.2 (c)", "ekeke"), 
     ("12.2 (d)", "qwerty"), 
     ("2.1","baala"),
     ("3","yuio"),
     ("4","poku"),
     ("5.2","qsdfg")]

My problem is as you can notice, at first it is good, though after "12.2 (d)" the list restart at "2.1",I don't how to solve this problem.

Thanks


Solution

  • Since the first element in each tuple is a string, Python is performing lexographic sorting in which all strings that start with '1' come before strings that start with a '2'.

    To get the sorting you desire, you'll want to treat the first entry as a float instead of a string.

    We can use sorted along with a custom sorting function which converts the first entry to a float prior to sorting. It also keeps the second tuple element to handle the case when you may have non-unique first entries.

    result = sorted(L, key = lambda x: (float(x[0].split()[0]), x[1]))
    
    # [('1', 'blaabal'), ('1.2', 'bbalab'), ('2.1', 'baala'), ('3', 'yuio'), ('4', 'poku'), ('5.2', 'qsdfg'), ('10', 'ejej'), ('11.1', 'aaua'), ('12.1', 'ehjej'), ('12.2 (c)', 'ekeke'), ('12.2 (d)', 'qwerty')]
    

    I had to add in a x[0].split()[0] so that we split the first tuple element at the space and only grab the first pieces since some have values such as '12.2 (d)' and we only want the '12.2'.

    If the second part of that first element that we've discarded matters, then you could use a sorting function similar to the following which breaks that first element into pieces and converts just the first piece to a float and leaves the rest as strings.

    def sorter(value):
        parts = value[0].split()
    
        # Convert the first part to a number and leave all other parts as strings
        parts[0] = float(parts[0]);
    
        return (parts, value[1])
    
    result = sorted(L, key = sorter)