3

I am working on code which creates a list and then applies both the "or" and "and" conditions to do further action:

a= ["john", "carlos", "22", "70"]

if (("qjohn" or "carlos") in a) and (("272" or "70") in a):
    print "true"
else:
    print "not true"

output:

not true

when I do this:

a= ["john", "carlos", "22", "70"]

if ("qjohn" or "cdarlos" in a) and ("272" or "d70" in a):
    print "true"
else:
    print "not true"

output is "true"

What I am not getting is **carlos and 70** should be equal to true but it's printing "not true". What is the cause of this error? Thanks

SeeDerekEngineer
  • 770
  • 2
  • 6
  • 22
Ahsan Naseem
  • 1,046
  • 1
  • 19
  • 38
  • Not quite a dupe, but deals with the same basic issue: [How do I test one variable against multiple values?](https://stackoverflow.com/questions/15112125/how-do-i-test-one-variable-against-multiple-values) – glibdud Jul 27 '17 at 13:53

3 Answers3

7

Both approaches are incorrect. Keep in mind or is a short-circuit operator so it's not doing what you think it does:

it only evaluates the second argument if the first one is false.

However, non-empty strings are always True, so that the first case only checks for the containment of the first non-empty string while the second never performs the containment check with in at all, therefore, it is always True.

What you want is:

if ("qjohn" in a or "carlos" in a) and ("272"  in a or "70" in a):
   ...

If the items to test were longer, you could avoid repeating the or by using any which like or also short-circuits once one of the items test True:

if any(x in a for x in case1) and any(x in a for x in case2):
   ...
Moses Koledoye
  • 77,341
  • 8
  • 133
  • 139
  • Could be useful : https://stackoverflow.com/questions/16679272/priority-of-the-logical-statements-not-and-or-in-python – Darkaird Jul 27 '17 at 13:46
1
b = set(a)
if {"qjohn", "carlos"} & b and {"272", "70"} & b:
    ....

The conditional is True if the intersection of the sets results in a non-empty set (membership test) - testing the truthiness of a non-empty set is quite pythonic in this regard.


Alternatively, using set.intersection:

if {"qjohn", "carlos"}.insersection(a) and {"272", "70"}.insersection(a):
    ....
cs95
  • 379,657
  • 97
  • 704
  • 746
  • If you use the `intersection` method, there's no need to precompute the set `b`; the method can take any iterable as its argument. `{"qjohn", "carlos"}.intersection(a)`, etc. (Whether you would want to do this depends on how big `a` is in the first place.) – chepner Jul 27 '17 at 13:54
  • @chepner Thanks. I'm of the opinion that this is an underrated solution. – cs95 Jul 27 '17 at 13:55
0

The both are incorrect. You understood the logic false.

("qjohn" or "carlos") in a is equivalent to "qjohn" in a

and

"qjohn" or "cdarlos" in a is equivalent to "qjohn" or ("cdarlos" in a)

chepner
  • 497,756
  • 71
  • 530
  • 681
qvpham
  • 1,896
  • 9
  • 17