Python Forum
Simplifying multiple "or" conditions in if statement.
Thread Rating:
  • 1 Vote(s) - 5 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Simplifying multiple "or" conditions in if statement.
#1
The first if statement, with "in s" after each string works.  However,  the second if statement, combining the strings with parentheses does not.

It seems I shouldn't have to repeat "in s."  Is there a way?

s='Bob' 'Tom'

if 'Tom' in s or 'Bob' in s:

if ('Tom' or 'Bob') in s:
Reply
#2
https://python-forum.io/Thread-Multiple-...or-keyword
:)
Reply
#3
works for me
python 3.6.2
>>> s='Bob' 'Tom'
>>> s
'BobTom'
>>> ('Tom' or 'Bob')
'Tom'
>>> 'Tom' in s
True
>>> 'Bob' in s
True
>>> if ('Tom' or 'Bob') in s:
...     print('Yup')
...
Yup
>>>
Reply
#4
Be a little careful of the way you test an expression such as this.
What could be happening is that it is just taking one of the values and using that.
You probably should test if 'Bob' or 'Carol', 'Alice' or 'Bob', 'Ted' or 'Alice' and even 'Carol' or 'Bob' (i.e. is it just taking the first name) also produce the required result.
(The principle behind this is to test edge cases, and for false positives and false negatives.)
Susan
Reply
#5
Quote:works for me

I'm sorry, I mistyped my example.  I meant to search on something not in the string; in the corrected example Ed.

The first works but the second doesn't.  However, I was confused as "if ('Bob' or 'Ed') in s:" works.  Regardless, the link provided as a response helps.

s='Bob' 'Tom'

if 'Ed' in s or 'Bob' in s:

if ('Ed' or 'Bob') in s:
Reply
#6
if ('Ed' or 'Bob') in s:
This code checks always if 'Ed' in s:

The or operator is a binary operation, which is checking for trueness.
A str object with the length 0 is False. All other str objects are True.
With your code you'll always get 'Ed' after evaluating the expression.

What you want to do:

s = 'BobTom'

for name in ('Bob', 'Ed'):
    if name in s:
        print('Name {} is in {}'.format(name, s))
If you want to check if any of the names is in the string, you can write it more compact:

any(name in s for name in ('Bob', 'Ed'))
If you want to check if all the names are in the string, you can use the built-in function all:

all(name in s for name in ('Bob', 'Ed'))
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply
#7
(Jul-21-2017, 01:32 PM)DeaD_EyE Wrote: If you want to check if any of the names is in the string, you can write it more compact:

any(name in s for name in ('Bob', 'Ed'))

Wonderful.  I knew I could use a loop but was looking for something more compact.  However, I don't see the need for "any."  The following seems to work:

(name in s for name in ('Bob', 'Ed'))
Is there an advantage to using "any" I'm not seeing.  I understand using "all" if that's required.
Reply
#8
The last call is every time true, because it's a generator expression.

g = (name in s for name in ('Bob', 'Ed'))
print(g) # Nothing is evaluated, it evaluates lazy
print(next(g))
print(next(g))
print(next(g)) # this will raise a StopIteration
Python supports following shortcuts:
  1. List comprehension, which makes a new list
    [char for char in 'An Object which is iterable']
  2. Dict comprehension, which makes a new dict. The order is not preserved.
    [n: char for n, char in enumerare('An Object which is iterable')]
    # using here enumerate just for demonstration. If you want to count Elements in an iterable, just use collections.Counter
    # collections.Counter('An Object which is iterable')
  3. Set comprehension which makes a new set. A set is a collection of elements, which are Unique. The order is not preserved.
    {char for char in 'An Object which is iterable'}
    # for example, you'll see the whitespace only one time
  4. Generator expression, which makes a generator. A generator is only executed when iterating over it. The state between iterations is saved in the generator.
    g = (char for char in 'An Object which is iterable')
    for c in g:
        print(g)
    # or written as a function
    def gen():
        for c in 'An Object which is iterable':
            yield c # yield keyword makes a generator
    
    for c in gen():
        print(c)

Now we come to the point that, all() and any(), takes iterables and valuates to bool(element)

all([True, True, True]) == True
all([True, False, True]) == False # all elements have to be checked
any([False, False, True]) == True # iterates till end has been reached
any([False, True, False]) == True # stops after second iteration


You can also pass a generator expression functions, if they are the only argument. In this case you don't have to use the parenthesis twice.
any((e for e in [False])) # this is valid
any(e for e in [False]) # this is valid
If you have a function, which takes more than one argument, you have to use parenthesis for a generator expression:

def foo(iterable, start):
    for index, element in enumerate(iterable, start):
        print(index, element)


foo((word for word in ['Hello' ,'World']), 1) # this is valid

foo((word for word in ['Hello' ,'World']), 1)
# SyntaxError: Generator expression must be parenthesized if not sole argument
Install ipython for Python3, which gives you better tabulator completion.
Then play around inside the repl.
In [1]: s = 'BobTom'

In [2]: any(name in s for name in ('Bob', 'Ed'))
Out[2]: True

In [3]: all(name in s for name in ('Bob', 'Ed'))
Out[3]: False

In [4]: (name in s for name in ('Bob', 'Ed'))
Out[4]: <generator object <genexpr> at 0x7f916f882c50>

In [5]: bool(name in s for name in ('Bob', 'Ed'))
Out[5]: True

In [6]: bool([])
Out[6]: False

In [8]: bool(tuple())
Out[8]: False

In [9]: bool('')
Out[9]: False

In [10]: bool('Foo')
Out[10]: True

In [11]: bool('False')
Out[11]: True

In [12]: bool('0')
Out[12]: True

In [13]: [name in s for name in ('Bob', 'Ed')]
Out[13]: [True, False]

In [14]: {name in s for name in ('Bob', 'Ed')}
Out[14]: {False, True}

In [15]: {name: name in s for name in ('Bob', 'Ed')}
Out[15]: {'Bob': True, 'Ed': False}

In [16]: (name in s for name in ('Bob', 'Ed'))
I hope this explains the use of list/dict/set comprehensions and generator expressions a little bit.
When you're using the if statement, it evaluates the bool. The object itself decides what it should return when __bool__() is called.

When calling bool(the_object)
  • empty string returns False
  • empty list returns False
  • empty tuple returns False
  • None returns False
  • 0 returns False
  • -1 returns True
  • 1 returns True
  • empty dict returns False
  • empty set returns False
  • normally all container types should return false, if they are empty
  • a function returns True
    def foo():
        pass
    bool(foo)
  • a generator returns True
    def gen():
        yield 1
    bool(gen)
  • a class returns True
    class Foo:
        pass
    bool(Foo)

You want to avoid the use of the three last examples. I am not sure about any use case to check the truthiness of a function, generator, class...
But you can do it accidentally, which gives you some output without an error, which leads to wrong conclusions.
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply
#9
(Jul-22-2017, 09:09 AM)DeaD_EyE Wrote: The last call is every time true, because it's a generator expression.
I hope this explains the use of list/dict/set comprehensions and generator expressions a little bit.

A good answer quite well explained.  I thank you kindly.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  How do you format Update statement with multiple conditions hammer 4 2,038 Dec-16-2021, 10:49 PM
Last Post: hammer
  multiple condition if statement problem FelixReiter 3 2,540 Jan-11-2021, 08:07 AM
Last Post: FelixReiter
  Multiple conditions when indexing an array with or without np.where noob2305 1 2,608 Oct-25-2020, 02:06 PM
Last Post: jefsummers
  Multiple conditions, one is null moralear27 1 2,165 Sep-13-2020, 06:11 AM
Last Post: scidam
  SyntaxError: multiple statements found while compiling a single statement Kayode_Odeyinka 1 2,934 Mar-12-2020, 05:50 PM
Last Post: micseydel
  multiple conditions Chandan 7 3,936 Jan-31-2020, 12:53 AM
Last Post: Chandan
  Help for simplifying code mmk1995 8 4,087 Sep-24-2019, 02:04 PM
Last Post: perfringo
  simplifying a stack of elifs Skaperen 8 3,998 Aug-17-2019, 04:13 AM
Last Post: Skaperen
  Simplifying my code ilondire05 5 3,689 Jul-21-2019, 03:21 AM
Last Post: scidam
  SyntaxError: multiple statements found while compiling a single statement DragonG 1 5,393 Nov-26-2018, 05:33 AM
Last Post: Larz60+

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020