0

I have something like:

a = [4,3,1,6,3,5,3]
b = [4,2,6]

and I wanted to remove the 3 elements of b from a. I was trying to do:

c = a - b

but I was thinking that the inverse of merge (+) might not be a thing, and was correct: Unsupported Operand types for -: list and list. I was contemplating just looping over them, but that just doesnt really sound pythony.

My end state is going to be: c = [3,1,3,5,3]

If you had not noticed, b is not a subset of a and these are unordered. 2 different sets, these sets are not unique either, but only want to remove 1 instance per i in b, not all instance of i in b

EDIT It seems that the current answer does not resolve my question.

a = [1,1,2,2,2,3,4,5]
b = [1,3]
c = [x for x in a if x not in b]
#c result is [2,2,2,4,5]

I want c to return: [1,2,2,2,4,5]

For the sake of speed typing, I just put sorted numbers, but the lists ARE IN FACT unsorted, though for the sake of cleanliness we can sort them.

They are just unsorted at init. Since there are duplicates in list items, I can't use a set as per the definition of set.

David Ansermot
  • 6,052
  • 8
  • 47
  • 82
Fallenreaper
  • 10,222
  • 12
  • 66
  • 129
  • Are these sets or lists? –  May 12 '16 at 14:29
  • lists, sorry, wrong wordage – Fallenreaper May 12 '16 at 14:32
  • 1
    Your last paragraph is not clear. If there is a `4` in list `b` and there are two occurrences of `4` in list `a`, do you want to remove one of the `4`'s or all of the `4`'s from `a`? – Rory Daulton May 12 '16 at 14:42
  • 1
    **For the Record** The duplicates are not the correct answer, nor is ysearka's..... DAX gave me the correct answer, as i only wanted to remove a particular number of instances, not *all* of a particular type. – Fallenreaper May 12 '16 at 15:06

4 Answers4

8

You can use the following code:

[x for x in a if x not in b]
ysearka
  • 3,805
  • 5
  • 20
  • 41
  • This is what i was thinking of, but couldnt get it down. For some reason, i kept trying to leverage bitwise operation on the lists. – Fallenreaper May 12 '16 at 14:39
  • @Fallenreaper: "but only want to remove 1 instance per i in b, not all instance of i in b" -> if this is a working answer then please adjust your question, as currently your last paragraph conflicts with this answer ... – DAXaholic May 12 '16 at 14:47
  • @DAXaholic you are in fact correct. I ran the code snipperts and noticed this wasnt the answer. – Fallenreaper May 12 '16 at 14:59
2

As input and output lists are unordered, use Counter is a way to go:

from collections import Counter

a = [4,3,1,6,3,5,3]
b = [4,2,6]
c = list((Counter(a) - Counter(b)).elements())

print(c)

This solution handles the following case differently than ysearka answer:

a = [4,3,1,6,3,5,3]
b = [3]

Where many answers here leads to c = [4,1,6,5], the one using Counter will outputs c = [4,1,6,3,3,5].

This behavior is also implemented by DAXaholic answer, but with modification of an existing list, which is not a pythonic way to go, and could be costly on big lists.

Community
  • 1
  • 1
aluriak
  • 5,559
  • 2
  • 26
  • 39
1

As you noted you only want to remove the items once per occurrence:

for x in [tmp for tmp in b if tmp in a]:
        a.remove(x)
DAXaholic
  • 33,312
  • 6
  • 76
  • 74
  • is it possible to not override a and just do assignment to a new varaible? Just something like:`c = [x for x in a]\n for x in [tmp for tmp in b if tmp in c]: c.remove(x)` – Fallenreaper May 12 '16 at 15:01
  • You could use e.g. aluriak's answer which has a few more lines but does not mutate your lists. – DAXaholic May 12 '16 at 15:28
0
for x in b:
    while x in a:
        a.remove(x)

Now a is

[3, 1, 3, 5, 3]