If you want a one-liner solution (ignoring imports) that only requires O(max(n, m))
work for inputs of length n
and m
, not O(n * m)
work, you can do so with the itertools
module:
from itertools import filterfalse
main_list = list(filterfalse(set(list_1).__contains__, list_2))
This takes advantage of the functional functions taking a callback function on construction, allowing it to create the callback once and reuse it for every element without needing to store it somewhere (because filterfalse
stores it internally); list comprehensions and generator expressions can do this, but it's ugly.†
That gets the same results in a single line as:
main_list = [x for x in list_2 if x not in list_1]
with the speed of:
set_1 = set(list_1)
main_list = [x for x in list_2 if x not in set_1]
Of course, if the comparisons are intended to be positional, so:
list_1 = [1, 2, 3]
list_2 = [2, 3, 4]
should produce:
main_list = [2, 3, 4]
(because no value in list_2
has a match at the same index in list_1
), you should definitely go with Patrick's answer, which involves no temporary list
s or set
s (even with set
s being roughly O(1)
, they have a higher "constant" factor per check than simple equality checks) and involves O(min(n, m))
work, less than any other answer, and if your problem is position sensitive, is the only correct solution when matching elements appear at mismatched offsets.
†: The way to do the same thing with a list comprehension as a one-liner would be to abuse nested looping to create and cache value(s) in the "outermost" loop, e.g.:
main_list = [x for set_1 in (set(list_1),) for x in list_2 if x not in set_1]
which also gives a minor performance benefit on Python 3 (because now set_1
is locally scoped in the comprehension code, rather than looked up from nested scope for each check; on Python 2 that doesn't matter, because Python 2 doesn't use closures for list comprehensions; they operate in the same scope they're used in).