Get uncommon items between 2 lists

Viewed 620

I have 2 lists 'a1' and 'a2':

a1 = [[1, 4], [1, 10], [2, 5], [2, 11], [3, 6], [4, 7], [4, 12], [5, 8], [5, 13], 
      [6, 9], [7, 14], [8, 15], [2, 10], [3, 11], [5, 12], [6, 13], [8, 14], [9, 15]]

a2 = [[1, 10], [2, 11], [4, 12], [5, 13], [7, 14], [8, 15], [2, 10], [3, 11], [5, 12], 
      [6, 13], [8, 14], [9, 15]]

I am looking to create a third list that contains the uncommon elements between the 2 previous lists, I should have something like this.

[[1, 4], [2, 5], [3, 6], [4, 7], [5, 8], [6, 9]]

Set difference could be applied to extract the elements of the first list that do not contain the second.

a3 = a1.difference(a2)

The problem is that it works for 2 lists, not for 2 lists of lists as in this case.

Is there an effective solution for this type of case? Best regards.

4 Answers

Your code will work if you define a1 and a2 as sets of tuples:

a1 = {(1, 4), (1, 10), (2, 5), (2, 11), (3, 6), (4, 7), (4, 12), (5, 8), (5, 13), (6, 9), (7, 14), (8, 15), (2, 10), (3, 11), (5, 12), (6, 13), (8, 14), (9, 15)}
a2 = {(1, 10), (2, 11), (4, 12), (5, 13), (7, 14), (8, 15), (2, 10), (3, 11), (5, 12), (6, 13), (8, 14), (9, 15)}
a3 = a1.difference(a2)
print(a3)

You could use a list comprehension that checks if elements from a1 exist in the set version of a2. Since lists are not hashable, we can use tuples instead.

# Convert a2 elements to a set of tuples
a2_set = {tuple(sublst) for sublst in a2}

# Use a list comprehension to filter the elements from a1 that don't exist in a2
difference = [sublst for sublst in a1 if tuple(sublst) not in a2_set]

print(difference)

Output:

[[1, 4], [2, 5], [3, 6], [4, 7], [5, 8], [6, 9]]

If we don't care about order(sets are unordered), we can convert a1 and a2 to sets of tuples and apply set difference using a - b or a.difference(b):

print(a1_set - a2_set)
# {(5, 8), (1, 4), (3, 6), (2, 5), (6, 9), (4, 7)}

print(a1_set.difference(a2_set))
# {(5, 8), (1, 4), (3, 6), (2, 5), (6, 9), (4, 7)}

We could also turn these results into nested lists using list comprehensions:

print([list(tup) for tup in a1_set - a2_set])
# [[5, 8], [1, 4], [3, 6], [2, 5], [6, 9], [4, 7]]

print([list(tup) for tup in a1_set.difference(a2_set)])
# [[5, 8], [1, 4], [3, 6], [2, 5], [6, 9], [4, 7]]

However if you want the symmetric difference, as explained in the docs:

Return a new set with elements in either the set or other but not both.

We can calculate the symmetric difference using either a ^ b or a.symmetric_difference(b):

a1_set = {tuple(sublst) for sublst in a1}
a2_set = {tuple(sublst) for sublst in a2}

print(a1_set ^ a2_set)
# {(5, 8), (6, 9), (1, 4), (4, 7), (3, 6), (2, 5)}

print(a1_set.symmetric_difference(a2_set))
# {(5, 8), (6, 9), (1, 4), (4, 7), (3, 6), (2, 5)}

Which can also be converted from a set of tuples to nested using list comprehensions:

print([list(tup) for tup in a1_set ^ a2_set])
# [[5, 8], [6, 9], [1, 4], [4, 7], [3, 6], [2, 5]]

print([list(tup) for tup in a1_set.symmetric_difference(a2_set)])
# [[5, 8], [6, 9], [1, 4], [4, 7], [3, 6], [2, 5]]

I think you could perform this for the lists before applying the difference function

a1 = set(tuple(pair) for pair in a1)

and then you could achieve what you are trying to

a3 = a1.difference(a2)
Related