Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort a list by presence of items in another list

Suppose I have two lists:

a = ['30', '10', '90', '1111', '17']
b = ['60', '1201', '30', '17', '900']

How would you sort this most efficiently, such that:

list b is sorted with respect to a. Unique elements in b should be placed at the end of the sorted list. Unique elements in a can be ignored.

example output:

c = ['30', '17', '60', '1201', '900']

Sorry, it's a simple question. My attempt is stuck at the point of taking the intersection.

intersection = sorted(set(a) & set(b), key = a.index)
like image 796
William Avatar asked Feb 13 '20 15:02

William


2 Answers

There is no need to actually sort here. You want the elements in a which are in b, in the same order as they were in a; followed by the elements in b which are not in a, in the same order as they were in b.

We can just do this with two filters, using the sets for fast membership tests:

>>> a = ['30', '10', '90', '1111', '17']
>>> b = ['60', '1201', '30', '17', '900']
>>> a_set = set(a)
>>> b_set = set(b)
>>> [*filter(lambda x: x in b_set, a), *filter(lambda x: x not in a_set, b)]
['30', '17', '60', '1201', '900']

Or if you prefer comprehensions:

>>> [*(x for x in a if x in b_set), *(x for x in b if x not in a_set)]
['30', '17', '60', '1201', '900']

Both take linear time, which is better than sorting.

like image 192
kaya3 Avatar answered Sep 24 '22 11:09

kaya3


You can create a custom dictionary, with the keys being the entries in a and the values their position. Then sort b according to the values in the dictionary. You can use dict.get for the lookup and inf if the value is not present:

a = ['30', '10', '90', '1111', '17']
b = ['60', '1201', '30', '17', '900']

d = {i:ix for ix, i in enumerate(a)}
#{'30': 0, '10': 1, '90': 2, '1111': 3, '17': 4}
sorted(b, key=lambda x: d.get(x, float('inf')))
#['30', '17', '60', '1201', '900']
like image 24
yatu Avatar answered Sep 23 '22 11:09

yatu