2

I have two lists

a = [1,1,2,3]
b = [1,2]

I need a new list c to have the answer which is derived by removing common elements of list b from list a. Which means if b has 1,2 then after removing from a the new list should have 1,3 as elements.

[1,3]

I tried

d = set(a) & set(b)
c = set(a) - d
print c

but I got

[3]

instead of

[1,3]

I know this is because the moment i do set(a) the repeated elements are trucncated and I am left with only one copy of all elements in there.

But my problem is that I want the repeated elements should not be removed.

What to do?

  • related: http://stackoverflow.com/questions/2727650/common-elements-between-two-lists-not-using-sets-in-python?rq=1 – NightShadeQueen Jul 24 '15 at 05:14
  • 2
    `repeated elements should not be removed` - then do not use set. The whole point of this datastructure is to remove duplicates – Konstantin Jul 24 '15 at 05:15
  • Why would you expect that result rather than the one you got? `set(a)` contains 1, 2 and 3, `set(b)` contains 1 and 2 so `set(d) will contain 1 and 2. Removing 1 and 2 from `set(a)` would only leave 3 which makes `set(a)-d` contains precisely 3. – skyking Jul 24 '15 at 05:50

4 Answers4

2

You can use collections.Counter -

>>> a = [1,1,2,3]
>>> b = [1,2]
>>> from collections import Counter
>>> c = list((Counter(a) - Counter(b)).elements())
>>> c
[1, 3]

What this does is that it counts the elements in list a and then in list b , and then it decreases the count in list a by the count of similar elements in list b , and converts them back to a list and stores in c.

This would even work if b has elements that are not in a, example -

>>> a = [1,1,2,3]
>>> b = [1,2,4]
>>> list((Counter(a) - Counter(b)).elements())
[1, 3]
Anand S Kumar
  • 88,551
  • 18
  • 188
  • 176
1

You do not need set and other packages. Importing additional packages "may" be expensive in terms of resources.

Try this.

c = list(a)
for data in b:
    if data in c: 
        c.remove(data)

To ignore, you may use try-except block.

c = list(a)
for data in b:
    try:
        c.remove(data)
    except ValueError:
        pass
soumen
  • 66
  • 5
0

You can use remove() to remove just one occurrence and a loop. For example:

a = [1,1,2,3]
b = [1,2]
# Create a copy of a so you don't modify a itself
c = list(a)
for num in b:
    c.remove(num)

print c
mongjong
  • 479
  • 3
  • 6
0

Counter is handy for this, but it has a reputation of being quite slow. Here is a version using defaultdict instead.

>>> from collections import defaultdict
>>> D = defaultdict(int)
>>> a = [1,1,2,3]
>>> b = [1,2]
>>> for k in a:
...     D[k] += 1
... 
>>> for k in b:
...     D[k] -= 1
... 
>>> [k for k in D for i in range(D[k])]
[1, 3]

Here is another way that retains the order of a in the result

>>> D = defaultdict(int)
>>> a = [1,1,2,3]
>>> b = [1,2]
>>> for k in b:
...     D[k] += 1
... 
>>> res = []
>>> for i in a:
...     if D[i]:
...         D[i] -= 1
...     else:
...         res.append(i)
... 
>>> res
[1, 3]
John La Rooy
  • 295,403
  • 53
  • 369
  • 502