Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Positioning of conditional statement within a python list comprehension with multiple iterables

I'm having a hard time understanding why the positioning of an identical conditional statement within a list comprehension of multiple iterables would affect the result.

>>> boys = 'Jim','Jeff'
>>> girls = 'Bonnie', 'Buffy'

# This generates four tuples as expected
>>> [(b,g) for b in boys for g in girls]
[('Jim', 'Bonnie'), ('Jim', 'Buffy'), ('Jeff', 'Bonnie'), ('Jeff', 'Buffy')]

# If the conditional "if b[-1] not in g" is at the end of the LC we get 3
>>> [(b,g) for b in boys for g in girls if b[-1] not in g]
[('Jim', 'Bonnie'), ('Jim', 'Buffy'), ('Jeff', 'Bonnie')]

# If the conditional is after the first sequence, we only get two results
>>> [(b,g) for b in boys if b[-1] not in g for g in girls]
[('Jim', 'Bonnie'), ('Jim', 'Buffy')]

Apologies in advance if someone else has already asked/answered this question on StackOverflow.

like image 201
damzam Avatar asked Jul 05 '26 00:07

damzam


1 Answers

What you did is the same as:

>>> boys = 'Jim','Jeff'
>>> girls = 'Bonnie', 'Buffy'
>>>
>>> out = []
>>> for b in boys:
...    for g in girls:
...       out.append((b,g))
...
>>> out
[('Jim', 'Bonnie'), ('Jim', 'Buffy'), ('Jeff', 'Bonnie'), ('Jeff', 'Buffy')]
>>>
>>> out = []
>>> for b in boys:
...    for g in girls:
...        if b[-1] not in g:
...            out.append((b,g))
...
>>> out
[('Jim', 'Bonnie'), ('Jim', 'Buffy'), ('Jeff', 'Bonnie')]
>>>
>>> b
'Jeff'
>>> g
'Buffy'
>>> out = []
>>> for b in boys:
...     if b[-1] not in g:
...         for g in girls:
...            out.append((b,g))
...
>>> out
[('Jim', 'Bonnie'), ('Jim', 'Buffy')]

Since b and g are already defined and filled with values from the last run, the following happens:

  • First outer loop Jim.
    • m in Buffy? No - run inner loop:
    • Append (Jim, Bonnie)
    • Append (Jim, Buffy)
  • Second outer loop Jeff
    • f in Buffy? Yes - skip inner loop.

If you had run this first in a new Python shell, it would have raised an Exception:

>>> # b = g = None 
>>> boys = 'Jim','Jeff'
>>> girls = 'Bonnie', 'Buffy'
>>>
>>> [(b,g) for b in boys if b[-1] not in g for g in girls]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <listcomp>
UnboundLocalError: local variable 'g' referenced before assignment
like image 54
Tim Pietzcker Avatar answered Jul 06 '26 13:07

Tim Pietzcker



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!