102

In Python you can use a.intersection(b) to find the items common to both sets.

Is there a way to do the disjoint opposite version of this? Items that are not common to both a and b; the unique items in a unioned with the unique items in b?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
user4847061
  • 1,223
  • 2
  • 9
  • 8

5 Answers5

192

You are looking for the symmetric difference; all elements that appear only in set a or in set b, but not both:

a.symmetric_difference(b)

From the set.symmetric_difference() method documentation:

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

You can use the ^ operator too, if both a and b are sets:

a ^ b

while set.symmetric_difference() takes any iterable for the other argument.

The output is the equivalent of (a | b) - (a & b), the union of both sets minus the intersection of both sets.

Producing the output takes O(M+N) time for sets of length M and N, respectively; M steps to copy set a then N steps to alter that set based on each value in b:

def symmetric_difference(a, b):
    result = set(a)
    for elem in b:
        try:
            result.remove(elem)
        except KeyError:
            result.add(elem)
    return result

There are in-place variants too, where set a is altered directly; use a.symmetric_difference_update(b) or a ^= b. The in-place variant takes O(N) time, so it depends on the size of set b only:

def symmetric_difference_update(a, b):
    for elem in b:
        try:
            a.remove(elem)
        except KeyError:
            a.add(elem)
    # no return, a has been updated in-place
Kelly Bundy
  • 23,480
  • 7
  • 29
  • 65
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Isn't ^ normaly XOR operator? – user4847061 Apr 29 '15 at 15:31
  • 1
    @user4847061: it is, but sets have overloaded several such operators. `|` and `&` are normally bitwise OR and bitwise AND, but on sets they give you the union and the intersection. The comparison operators `<`, `<=`, `>` and `>=` have been overloaded too. – Martijn Pieters Apr 29 '15 at 15:34
6
a={1,2,4,5,6}
b={5,6,4,9}
c=(a^b)&b
print(c) # you got {9}
Kaung Yar Zar
  • 69
  • 1
  • 1
  • Why did you add an intersection operation here? This is not the inverse of the intersection, it is the (asymmetric) difference between `b` and `a`. This could have been expressed as `b - a` instead, a far simpler expression! The symmetric difference and true inverse of the intersection of an and b is `{1, 2, 9}` and you had that with `a ^ b`. – Martijn Pieters Mar 22 '23 at 10:22
2

The best way is a list comprehension.

a = [ 1,2,3,4]
b = [ 8,7,9,2,1]
c = [ element for element in a if element not in b] 
d = [ element for element in b if element not in a] 
print(c) 
# output is [ 3,4]
print(d) 
# output is  [8,7,9]

You can join both lists

Apeasant
  • 177
  • 8
  • 3
    The performance on a list comprehension, when compared to a set for the above operations, is MUCH slower. It's okay for small lists, but for large operations, it can take hours and days. – Joe B Nov 16 '20 at 20:34
  • Thanks for pointing this out i didn't knew about it as my lists are not usually long ones. – Apeasant Nov 30 '21 at 10:00
  • The question asked about **sets**, not lists. There is a reason for that: the symmetric difference can be produced in O(M+N) time, where M and N are the lengths of the two sets. Your loops take O(MxN) time, for lengths M and N. Try using this with lists length 100 and 1000, then grow this lists by a factor of 10 and try again. Now compare how long it takes if you started with sets. – Martijn Pieters Mar 22 '23 at 10:22
  • Note that you also produce two separate (asymmetric) difference results; that’s not quite the inverse of the intersection. You’d need to join the two lists for that. – Martijn Pieters Mar 22 '23 at 10:35
  • If you **must** have a list then at least convert the longer list to a set first, loop over the shorter list and select all the elements missing from that set while adding those that are not missing to a second set. Then loop over the longer list and select all those elements that are missing in the second set to the output. That’s also an O(N+M) operation. – Martijn Pieters Mar 22 '23 at 10:37
-1

e, f are two list you want to check disjoint

a = [1,2,3,4]
b = [8,7,9,2,1]

c = []
def loop_to_check(e,f):
    for i in range(len(e)):
        if e[i] not in f:
            c.append(e[i])


loop_to_check(a,b)
loop_to_check(b,a)
print(c)

## output is [3,4,8,7,9]

This loops around to list and returns the disjoint list

buda__
  • 41
  • 1
  • 5
  • This has terrible performance because `value in list` has to check every element in the list for equality; for inputs of length N and M this will take O(MxN) time. The set operation on the other hand only take O(M+N) time where K is the shortest length of the two sets. Try using this on two lists with 1000 elements. Try again with 10000 elements. The question asked about *sets* for a reason. – Martijn Pieters Mar 22 '23 at 10:26
-2

Try this code for (set(a) - intersection(a&b))

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

for i in b:
   if i in a:
      a.remove(i)

print(a)

the output is [1,4,5,6] I hope, it will work

  • 2
    It's usually bad to mutate lists you are iterating over (in this case, there is no real consequence, unless I only care about returning a new list and not modifying `a`). Also `check = i in a` is redundant since you can always `if i in a:` – cowbert Mar 14 '18 at 20:26
  • @cowbert thanks for your advise. I have fixed it. I will learn more about that. – Muhammad Ammar Fauzan Mar 16 '18 at 23:11
  • You can try with this one-liner solution `print(sorted(set(a)-set(b)))` – ravibeli Mar 13 '20 at 09:20
  • I believer that is called the **relative complement** or **difference** of two sets. – ingyhere May 05 '20 at 16:42
  • using numpy this case become easier np.setdiff1d(a, b) – Muhammad Ammar Fauzan May 07 '20 at 15:57
  • The question asks about sets, not lists, and this produces the (asymmetric) difference between an and b. That’s not the inverse of the intersection, that’s a *symmetric* difference, so the union of `a - b` and `b - a`. Try adding `7` to `b` here, it would be included in a symmetric difference. – Martijn Pieters Mar 22 '23 at 10:31