Home > Back-end >  Sorting enumerated elements in a list using another list as an order
Sorting enumerated elements in a list using another list as an order

Time:01-29

I have a master list:

l = ['gala_apple', 'gala_lime', 'fuji_apple', 'fuji_lime']

Through some manipulation, I end up with a variant of l:

r = [
    'fuji_apple_1',
    'fuji_apple_2',
    'fuji_lime_1',
    'fuji_lime_2',
    'gala_apple_1',
    'gala_apple_2',
    'gala_apple_3',
    'gala_lime_1',
    'gala_lime_2',
    'gala_lime_3',
]

Using the master list l as a reference, I want the list r to be ordered like:

r = [
    'gala_apple_1',
    'gala_lime_1',
    'gala_apple_2',
    'gala_lime_2',
    'gala_apple_3',
    'gala_lime_3',
    'fuji_apple_1',
    'fuji_lime_1',
    'fuji_apple_2',
    'fuji_lime_2',
]

I.e. (gala_apple_X, gala_lime_X, gala_apple_Y, gala_lime_Y, ...), (fuji_apple_X, fuji_lime_X, fuji_apple_Y, fuji_lime_Y, ...)

CodePudding user response:

This works, but for scaling to more variables (e.g. gala_grape, gala_pear), you need to change the for-loop and, in general, the algorithm isn't very efficient.

r2 = []
for apple, lime in zip(l[0::2], l[1::2]):
    for i in range(len(r)):
        a_i = f'{apple}_{i}'
        if a_i in r:
            r2.extend([a_i, f'{lime}_{i}'])
print(r2)

CodePudding user response:

First use l to derive sort orders for the type (gala, fuji, etc) and fruit (apple, lime, etc):

>>> taxonomy = {}
>>> for x in l:
...     t, f = x.split("_")
...     taxonomy.setdefault(t, []).append(f)
... 
>>> type_order = {t: i for i, t in enumerate(taxonomy)}
>>> fruit_orders = {tuple(v) for v in taxonomy.values()}
>>> assert len(fruit_orders) == 1  
>>> fruit_order = {t: i for i, t in enumerate(fruit_orders.pop())}

That gives us:

>>> type_order
{'gala': 0, 'fuji': 1}
>>> fruit_order
{'apple': 0, 'lime': 1}

Then use that to define a sort key function which sorts first on type (the first field), then on number (the third field), then on fruit (the second field), using the established sort order for type and fruit, and numeric sort order for the number:

>>> def sort_key(x):
...     t, f, n = x.split("_")
...     return type_order[t], int(n), fruit_order[f]
... 

Then you can use that key to sort r:

>>> print(*sorted(r, key=sort_key), sep='\n')
gala_apple_1
gala_lime_1
gala_apple_2
gala_lime_2
gala_apple_3
gala_lime_3
fuji_apple_1
fuji_lime_1
fuji_apple_2
fuji_lime_2
  • Related