Search code examples
pythonsortingenumerate

Enumerate a list sorted by two fields in Python


I have an array of this kind:
field 4 is the mean of 1,2,3, and field 5 is the min of 1,2,3.

[['name0', 24, 19, 25, 22.67, 19],
 ['name1', 25, 19, 25, 23.0, 19],
 ['name2', 25, 19, 25, 23.0, 19],
 ['name3', 24, 22, 23, 23.0, 22],
 ['name4', 27, 19, 25, 23.67, 19],
 ['name5', 27, 19, 25, 23.67, 19],
 ['name6', 28, 19, 26, 24.33, 19],
 ['name7', 28, 19, 26, 24.33, 19],
 ['name8', 28, 19, 26, 24.33, 19],
 ['name9', 26, 22, 27, 25.0, 22],
 ['name10', 27, 23, 25, 25.0, 23],
 ['name11', 30, 19, 27, 25.33, 19],
 ['name12', 24, 31, 28, 27.67, 24],
 ['name13', 28, 27, 28, 27.67, 27],
 ['name14', 27, 29, 27, 27.67, 27],
 ['name15', 29, 26, 29, 28.0, 26],
 ['name16', 29, 26, 30, 28.33, 26],
 ['name17', 30, 31, 26, 29.0, 26],
 ['name18', 33, 27, 30, 30.0, 27],
 ['name19', 29, 31, 30, 30.0, 29],
 ['name20', 30, 36, 31, 32.33, 30],
 ['name21', 36, 30, 32, 32.67, 30],
 ['name22', 38, 33, 36, 35.67, 33],
 ['name23', 30, 27, 99, 52.0, 27],
 ['name24', 99, 27, 32, 52.67, 27],
 ['name25', 37, 99, 36, 57.33, 36]]

Which has been sorted by field 4 then by field 5.
I'd wish to enumerate this list, creating a sort of "ranking" or "podium".

enumerate() doesn't work because as you can see, some fields are tied on field 4 and 5, so their "rank" should be the same.
As an example, the first values should look like:

[['1', 'name0', 24, 19, 25, 22.67, 19],
 ['2', 'name1', 25, 19, 25, 23.0, 19],
 ['2', 'name2', 25, 19, 25, 23.0, 19],
 ['3', 'name3', 24, 22, 23, 23.0, 22],
 ['4', 'name4', 27, 19, 25, 23.67, 19],
 ...]

Couldn't figure out a clean way to approach this. Thanks for the help.


Solution

  • Assuming that the list is sorted, you can group the sub-lists by their 4th and 5th elements using ... the aptly-named groupby, and itemgetter. Use enumerate on the iterator returned by groupby:

    from itertools import groupby
    from operator import itemgetter
    
    # data = [['name0', ...
    [ [str(i+1)] + l for i, (k, g) in enumerate(groupby(data, key=itemgetter(4, 5))) for l in g ]
    

    Output:

    [
        ['1', 'name0', 24, 19, 25, 22.67, 19],
        ['2', 'name1', 25, 19, 25, 23.0, 19],
        ['2', 'name2', 25, 19, 25, 23.0, 19],
        ['3', 'name3', 24, 22, 23, 23.0, 22],
        ['4', 'name4', 27, 19, 25, 23.67, 19],
        ['4', 'name5', 27, 19, 25, 23.67, 19],
        ['5', 'name6', 28, 19, 26, 24.33, 19],
        ['5', 'name7', 28, 19, 26, 24.33, 19],
        ['5', 'name8', 28, 19, 26, 24.33, 19],
        ['6', 'name9', 26, 22, 27, 25.0, 22],
        ['7', 'name10', 27, 23, 25, 25.0, 23],
        ['8', 'name11', 30, 19, 27, 25.33, 19],
        ['9', 'name12', 24, 31, 28, 27.67, 24],
        ['10', 'name13', 28, 27, 28, 27.67, 27],
        ['10', 'name14', 27, 29, 27, 27.67, 27],
        ['11', 'name15', 29, 26, 29, 28.0, 26],
        ['12', 'name16', 29, 26, 30, 28.33, 26],
        ['13', 'name17', 30, 31, 26, 29.0, 26],
        ['14', 'name18', 33, 27, 30, 30.0, 27],
        ['15', 'name19', 29, 31, 30, 30.0, 29],
        ['16', 'name20', 30, 36, 31, 32.33, 30],
        ['17', 'name21', 36, 30, 32, 32.67, 30],
        ['18', 'name22', 38, 33, 36, 35.67, 33],
        ['19', 'name23', 30, 27, 99, 52.0, 27],
        ['20', 'name24', 99, 27, 32, 52.67, 27],
        ['21', 'name25', 37, 99, 36, 57.33, 36]
    ]