taga
taga

Reputation: 3885

Removing elements from multiple lists that can appear in other lists

I have 3 lists:

l1 = ['a', 'b', 'c', 'd', 'e', 'q', 'w']
l2 = ['a', 'g', 'h', 'd', 'k']
l3 = ['z', 'b', 'v', 'n', 'k', 's']

I want to create some kind of filter, that will leave only unique elements in these 3 lists. So l1 should have only elements that are not in l2 and l3, and I want to do the same for every list. Desired output:

l1 = ['c', 'e', 'q', 'w']
l2 = ['g', 'h']
l3 = ['z', 'v', 'n', 's']

I have 6 lists with more than 5000 elements each, and lists are not the same length. I was thinking of doing some kind of intersections, but I'll have to make a lot of for loops.

Is there any Pythonic way for this?

Upvotes: 0

Views: 71

Answers (2)

Samwise
Samwise

Reputation: 71454

I'd use a Counter:

>>> l1 = ['a', 'b', 'c', 'd', 'e', 'q', 'w']
>>> l2 = ['a', 'g', 'h', 'd', 'k']
>>> l3 = ['z', 'b', 'v', 'n', 'k', 's']
>>> import collections
>>> counter = collections.Counter(l1 + l2 + l3)
>>> [i for i in l1 if counter[i] == 1]
['c', 'e', 'q', 'w']
>>> [i for i in l2 if counter[i] == 1]
['g', 'h']
>>> [i for i in l3 if counter[i] == 1]
['z', 'v', 'n', 's']

Note that if you have a bunch of lists you want to do exactly the same thing to, you probably just want to have a list of lists rather than a bunch of individual variables:

>>> all_lists = [l1, l2, l3]
>>> counter = collections.Counter(i for a in all_lists for i in a)
>>> [[i for i in a if counter[i] == 1] for a in all_lists]
[['c', 'e', 'q', 'w'], ['g', 'h'], ['z', 'v', 'n', 's']]

Upvotes: 7

cards
cards

Reputation: 4975

Here the set approach. It is combinatorics based so it depends on the amount of lists, n, only. The loop will always iterate n-times since "n choose n-1" = n.

Drawback: final lists will be (randomly) sorted

Advantage: "construction" exact solution

import itertools as it

l1 = ['a', 'b', 'c', 'd', 'e', 'q', 'w']
l2 = ['a', 'g', 'h', 'd', 'k']
l3 = ['z', 'b', 'v', 'n', 'k', 's']

ls = (l1, l2, l3)
# as dictionary with key integer numbers and values sets
d = {i: set(ls[i]) for i in range(len(ls))}

results = []
s = set(d.keys())
for p in it.combinations(d.keys(), len(ls)-1):
    # index not comparing in p
    i = tuple(s.difference(p))[0]
    # new set
    s_new = d[i].difference(set.union(*map(d.__getitem__, p)))
    results.append(list(s_new))

print(results)

Output

[['v', 's', 'n', 'z'], ['h', 'g'], ['e', 'c', 'w', 'q']]

Upvotes: 0

Related Questions