Home > OS >  How to change order of list based on common element in python?
How to change order of list based on common element in python?

Time:10-26

I have the following list:

l1 = ['foo_x', 'bar_x', 'xyz_x', 'foo_y', 'bar_y', 'xyz_y']

I created a list with common elements.

l2 = ['foo', 'bar', 'xyz']

# trying to reorder which is not successful

[i for i in l1 if (l2 in l1)]

I would like to change the order of l1 to have the following outcome:

['foo_x', 'foo_y', 'bar_x', 'bar_y', 'xyz_x', 'xyz_y']

CodePudding user response:

Assuming that each element in l1 is a superstring of some element in l2, you could use next to sort by the index of the first matching element.

>>> l1 = ['foo_x', 'bar_x', 'xyz_x', 'foo_y', 'bar_y', 'xyz_y']    
>>> l2 = ['foo', 'bar', 'xyz']
>>> sorted(l1, key=lambda x: next(i for i, e in enumerate(l2) if e in x))
['foo_x', 'foo_y', 'bar_x', 'bar_y', 'xyz_x', 'xyz_y']

The next means linear complexity (in size of l2) for each element in l1. If the _ is significant, i.e. if the elements in l2 are always the part before the _, you can create a dictionary mapping each element to its index and then look up that index directly using that substring.

>>> l2_idx = {e: i for i, e in enumerate(l2)}
>>> sorted(l1, key=lambda x: l2_idx[x[:x.index("_")]])
['foo_x', 'foo_y', 'bar_x', 'bar_y', 'xyz_x', 'xyz_y']

Both ways, in this form, would fail if there is no matching element in l2, but you can provide both with a default element to be used in that case, e.g. len(l2).

CodePudding user response:

IIUC, You need .split() then sort base index in l2 and last part after _ like below:

>>> l1 = ['foo_x', 'bar_x', 'xyz_x', 'foo_y', 'bar_y', 'xyz_y']

>>> l2 = ['foo', 'bar', 'xyz']

>>> sorted(l1, key=lambda x: (l2.index(x.split('_')[0]), x.split('_')[1]))
['foo_x', 'foo_y', 'bar_x', 'bar_y', 'xyz_x', 'xyz_y']

Another Example:

>>> l1 = ['foo_x', 'bar_x', 'xyz_x', 'foo_y', 'bar_y', 'xyz_y' , 'foo_a', 'bar_b', 'xyz_c']

>>> l2 = [ 'xyz' , 'foo', 'bar']

>>> sorted(l1, key=lambda x: (l2.index(x.split('_')[0]), x.split('_')[1]))
['xyz_c',
 'xyz_x',
 'xyz_y',
 'foo_a',
 'foo_x',
 'foo_y',
 'bar_b',
 'bar_x',
 'bar_y']
  • Related