If list1
and list2
are both guaranteed to contain only unique elements, you can turn list2
into a set
and select from list1
based on it:
set2 = set(list2)
list2_sorted = [x for x in list1 if x in set2]
If, on the other hand list2
contains non-unique elements, you can use collections.Counter
to do the same thing while maintaining optimal algorithmic complexity.
counter2 = Counter(list2)
list2_sorted = []
for x in list1:
list2_sorted.extend([x] * counter2[x])
The algorithmic complexity is the same here because python's list growing is amortized to provide O(n)
behavior in the long term, and the keys of a Counter
, or any other dict
, are implemented as a hash-table with O(1)
lookup, just like a set
.
You can use a nested comprehension instead of the loop:
list2_sorted = [x for x in list1 for _ in range(counter2[x])]
You can use the set-like behavior of dictionaries to maintain O(n)
behavior even if list1
contains duplicates, as long as the sort order is determined only by the first occurrence. In Python 3.6+ dictionaries are ordered, so you could use plain dict
. Prior versions would require you to use collections.OrderedDict
to obtain the same behavior:
list1_keys = OrderedDict.fromkeys(list1)
list2_sorted = [x for x in list1_keys for _ in range(counter2[x])]
The reason to use a dict
when you are looking for set
-like behavior is that set
is not ordered.