0

I got two sets and want to add the differences to a list with a list comprehension.

Using one set works perfectly fine: diff = [x for x in a.difference(b)]

However, when I try to include the second set (b) I get already a warning from PyCharm that the syntax is invalid.

Error message:

    diff = [x,y for x in a.difference(b) for y in b.difference(a)]
                  ^
SyntaxError: invalid syntax

Below is a web example and the comparative attempt with my input which creates lists within the diff list which I do not want.

Web Example: my_list = [x * y for x in [20, 40, 60] for y in [2, 4, 6]]

diff = [[x,y] for x in a.difference(b) for y in b.difference(a)]

Output: [[9, 11], [9, 12], [5, 11], [5, 12]]

Expected Output: [5,9,11,12]

What is the syntax to create one list with the set differences from two sets?

Alex_P
  • 2,580
  • 3
  • 22
  • 37

3 Answers3

2

It seems you are looking for the symmetric difference:

>>> a = set([1,2,3,9,5])
>>> b = set([1,2,3,11,12])
>>> a ^ b
{5, 9, 11, 12}

Or:

>>> a.symmetric_difference(b)
{5, 9, 11, 12}

If you want to do it with difference and union:

>>> a.difference(b).union(b.difference(a))
{9, 11, 12, 5}

Or:

>>> (a-b) | (b-a)
{9, 11, 12, 5}

To transform a set into a list:

>>> list(a ^ b)
[5, 9, 11, 12]

For a set comprehension method:

>>> set(x for t,u in [(a,b), (b,a)] for x in t if x not in u)
{9, 11, 12, 5}

It takes every element in a that is not in b then every element in b that is not in a.

jferard
  • 7,835
  • 2
  • 22
  • 35
  • the last one seems unnecessarily convoluted... but very comprehensive list of options! – Silly Freak Jul 29 '19 at 10:22
  • @SillyFreak the last one is there because of the `list-comprehension` tag, but you are right: I would never use it since higher level functions are available. – jferard Jul 29 '19 at 10:36
0

You can't do this from within the list comprehension–each element it returns is its own entity–but you can use itertools's chain.from_iterable to get what you want:

list(itertools.chain.from_iterable((x,y) for x in a.difference(b) for y in b.difference(a))

The list call is there because the chain functions just return lazy iterators. If that is ok with you, you can remove the list.

Turn
  • 6,656
  • 32
  • 41
  • I'd advise against this answer. Getting to the difference by flattening the list of pairs OP got is backwards, and also introduces duplicates. @Alex_P, take a look at jferard's answer, it has a number of ways that are way clearer and more direct than this one. – Silly Freak Jul 29 '19 at 10:26
0

Let's break down what the list comprehension is very roughly syntactic sugar for:

diff = []
for x in a.difference(b):
    for y in b.difference(a):
        diff.append([x,y])

The two fors are nested! I've added the brackets around x,y to make it a single value so that it works, like it is necessary in the list comprehension. I hope this explains why you got [[9, 11], [9, 12], [5, 11], [5, 12]]: one difference was {9, 5}, the other was {11, 12}. The result is the cartesian product of those sets, as a list.

What you want is basically a union. In "desugared" list comprehensions, that would be a sequence of for loops:

diff = []
for x in a.difference(b):
    diff.append(x)
for y in b.difference(a):
    diff.append(y)

The other answers, comments, and this question already show how to achieve what your ultimate goal is, so I won't repeat that, but this is why your code didn't do what you thought it should.

Silly Freak
  • 4,061
  • 1
  • 36
  • 58