2

I have the following code which works

[i for i in range(1, 16) if any(i % j == 0 for j in [3,5])]

This has an output of [3, 5, 6, 9, 10, 12, 15], the numbers that can be divided by either 3 or 5.

However, when I try

[i for i in range(1, 16) if any(i % j != 0 for j in [3,5])]

I get [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

What I'm looking for instead is [1, 2, 4, 7, 8, 11, 13, 14]

Many thanks!

Thanos Dodd
  • 572
  • 1
  • 4
  • 14

2 Answers2

3

You need to negate the condition and switch to all:

>>> [i for i in range(1, 16) if all(i % j != 0 for j in [3,5])]
[1, 2, 4, 7, 8, 11, 13, 14]

or leave the condition as-is and negate the result of any:

>>> [i for i in range(1, 16) if not any(i % j == 0 for j in [3,5])]
[1, 2, 4, 7, 8, 11, 13, 14]

Both can be derived from De Morgan's laws, one of which states that

not (A or B) == not A and not B

(which generalizes to not (A or B or ... ) == not A and not B and ...).

any(Ai for i in ...) is equivalent to A0 or A1 or A2 or ... or An, and all(Ai for i in ...) is equivalent to A0 and A1 and A2 or ... or An.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • I understand the second solution. In the first one I'm guessing conditions for all j need to be True. – Thanos Dodd Nov 14 '19 at 15:09
  • Correct. De Morgan's other law is that `not (A and B) == not A or not B`. `not (i % j != 0)` is the same as `i % j == 0` (and conversely, `not (i % j == 0)` is `i % j != 0`). – chepner Nov 14 '19 at 15:23
2

[i for i in range(1, 16) if not any(i % j == 0 for j in [3,5])]

Magiq
  • 116
  • 3