Suhail Pappu
Suhail Pappu

Reputation: 59

Efficiently remove elements from a list in python which are also in given lists

So I have two lists and one main list. The elements in the main list should be removed if they are present in either of the other two lists.

Example:

s1 = [1,2,3,4,7]
s2 = [3,4,5,6,20]
mainlist = [6,7,8,9,10,11,12,13,14,15]

So, as the mainList contains the elements 6 and 7 which are also present in either s1 or s2, they should be removed and the result should be like the following.

resultList = [8,9,10,11,12,13,14,15]

My code:

for j in mainlist[:]:
    if j in s1 or j in s2:
        mainlist.remove(j)

Is there anyway without using the for loop? I need an efficient way to reduce time complexity. Thank you !

Upvotes: 3

Views: 79

Answers (6)

music_junkie
music_junkie

Reputation: 189

You can convert s1 and s2 to dict

s1 = {i:i for i in s1}
s2 = {i:i for i in s2}
mainlist = [i for i in mainlist if i not in s1 or i not in s2]

You would lose some time with converting lists to dict, but since python dictionary is basically hash table, then search complexity is O(1) and not O(n) like with lists.
So in the end it would be not O(n^2), but O(n) or something like that.
Let me know if you try this.

Upvotes: 1

oppressionslayer
oppressionslayer

Reputation: 7214

You can also use counter to perform this:

from collections import Counter

print(list(Counter(mainlist) - Counter(s1) - Counter(s2)))
Out[309]: [8, 9, 10, 11, 12, 13, 14, 15]

Upvotes: 0

Akash Kumar
Akash Kumar

Reputation: 1406

Try this:

mainlist = list(set(mainlist) - (set(s1)|set(s2)))

Here I am assuming that none of the lists have repeated elements.

You can time and compare it from other methods.

time_idx = time()
result = [x for x in mainlist if x not in s1 and x not in s2]
print(time() - time_idx)

0.00012612342834472656

time_idx = time()
mainlist = list(set(mainlist) - (set(s1)|set(s2)))
print(time() - time_idx)

0.00010609626770019531

The improvement is significant since this is a small list.

Upvotes: 1

Saleem Ali
Saleem Ali

Reputation: 1383

Just use set operation to filter out

>>> list(set(mainlist) - set(s1+s2))
>>> [8, 9, 10, 11, 12, 13, 14, 15]

Upvotes: 0

Ryuzaki L
Ryuzaki L

Reputation: 40048

Probably you can create another list by using list comprehension

res = [i for i in test_list if i not in s1 and i not in s2]

or using filter() + lambda

res = filter(lambda i: i not in s1 and i not in s2, mainlist) 

or using for loop

for elem in mainlist:
   if elem in s1 or elem in s2:
      mainlist.remove(elem)

Upvotes: 2

azro
azro

Reputation: 54148

You can use list comprehension, it's ready good for that kind of problem :

result = [x for x in mainlist if x not in s1 and x not in s2]

Using list/set manipulation you can do one of the following

result = list(set(mainlist) - (set(s1) | set(s2)))  # remove the concat of s1&s2
result = list(set(mainlist) - set(s1) - set(s2))    # remove s1 and s2

Upvotes: 2

Related Questions