-3

I am currently making an interactive system using python, that is able to understand and reply. Hence for this there are lots of conditions for machine to analyze and process. For eg. take the following code(for reference only):

    if ('goodbye') in message:                          
        rand = ['Goodbye Sir', 'Jarvis powering off in 3, 2, 1, 0']
        speekmodule.speek(rand,n,mixer)
        break

    if ('hello') in message or ('hi') in message:
        rand = ['Wellcome to Jarvis virtual intelligence project. At your service sir.']
        speekmodule.speek(rand,n,mixer)

    if ('thanks') in message or ('tanks') in message or ('thank you') in message:
        rand = ['You are wellcome', 'no problem']
        speekmodule.speek(rand,n,mixer)

    if message == ('jarvis'):
        rand = ['Yes Sir?', 'What can I doo for you sir?']
        speekmodule.speek(rand,n,mixer)

    if  ('how are you') in message or ('and you') in message or ('are you okay') in message:
        rand = ['Fine thank you']
        speekmodule.speek(rand,n,mixer)

    if  ('*') in message:
        rand = ['Be polite please']
        speekmodule.speek(rand,n,mixer)

    if ('your name') in message:
        rand = ['My name is Jarvis, at your service sir']
        speekmodule.speek(rand,n,mixer)

So, is there a way in which I can replace all these if else conditions?? Because there are much more conditions going to be, and it will make the execution slower.

  • 1
    The first step is to remove unnecessary parens, i.e. just write `if 'hello'`. – skovorodkin Oct 02 '16 at 11:53
  • Here's a solution using dictionaries: http://stackoverflow.com/questions/60208/replacements-for-switch-statement-in-python – imant Oct 02 '16 at 11:53
  • Yes, you can use a dictionary as suggested to implement a kind of "switch … case …". But with RegEx in order to implement the "word in message". However, it won't reduce the complexity of your algorithm: you have to check all cases. – Laurent LAPORTE Oct 02 '16 at 11:57
  • My opinion : the conditions look exclusive, so use a `if … elif … else …` construct to initialize the ˋrand` variable and then run ˋspeekmodule.speek(rand, n, mixer)` only once. This will remain understandable and maintenable even if you have a big ˋif`. – Laurent LAPORTE Oct 02 '16 at 12:03

4 Answers4

1

if/elif/else is a natural way to structure this kind of code in Python. As @imant noted, you may use dict-based approach in case of simple branching, but I see some mildly complex logic in your if predicates, so you'll have to check all predicates in any case and you won't have any performance gains with another code structure.

Though it may be a little bit more readable and easier to maintain if you factor out your predicates and actions like this:

from collections import OrderedDict

def goodbye_p(message):
    return 'goodbye' in message

def goodbye_a():
    rand = ['Goodbye Sir', 'Jarvis powering off in 3, 2, 1, 0']
    # As @Moinuddin Quadri I also assume that your `speek` method
    # says random message from a list.
    # Otherwise you can use `random.choice` method 
    # to get a random message out of a list: `random.choice(messages)`.
    speekmodule.speek(rand, n, mixer)


def hello_p(message):
    return 'hello' in message or 'hi' in message

def hello_a():
    rand = ['Wellcome to Jarvis virtual intelligence project. At your service sir.']
    speekmodule.speek(rand, n, mixer)

# Use `OrderedDict` instead of `dict` to control order
# of checks and actions.
branches = OrderedDict([
    # (predicate as key, action as value)
    (goodbye_p, goodbye_a),
    (hello_p, hello_a),
])

for predicate, action in branches.items():
    if predicate(message):
        action_result = action()
        # You can add some logic here based on action results.
        # E.g. you can return some special object from `goodbye_a`
        # and then shut down Jarvis here.
        # Or if your actions are exclusive, you can add `break` here.

If all your predicates are the same and contain only substring checks, then it may be more performant to have tuples (e.g. ('hello', 'hi')) as dict keys. Then you can iterate over those keys like this:

for words, action in branches.items():
    if any(word in message for word in words):
        action()
skovorodkin
  • 9,394
  • 1
  • 39
  • 30
1

Make a exclusive "if":

if 'goodbye' in message:                          
    rand = ['Goodbye Sir', 'Jarvis powering off in 3, 2, 1, 0']

elif 'hello' in message or 'hi' in message:
    rand = ['Wellcome to Jarvis virtual intelligence project. At your service sir.']

elif 'thanks' in message or 'tanks' in message or ('thank you') in message:
    rand = ['You are wellcome', 'no problem']

elif message == 'jarvis':
    rand = ['Yes Sir?', 'What can I doo for you sir?']

elif  'how are you' in message or 'and you' in message or ('are you okay') in message:
    rand = ['Fine thank you']

elif  '*' in message:
    rand = ['Be polite please']

elif 'your name' in message:
    rand = ['My name is Jarvis, at your service sir']

else:
    raise NotImplementedError("What to do?")

speekmodule.speek(rand, n, mixer)

With a mapping of RegEx:

mapping = {
    r"\bgoodbye\b": ['Goodbye Sir', 'Jarvis powering off in 3, 2, 1, 0'],
    r"\bhello\b": ['Wellcome to Jarvis virtual intelligence project. At your service sir.'],
    ...}

for regex, rand in mapping.items():
    if re.search(message, flags=re.I):
        break
else:
    raise NotImplementedError("What to do?")
speekmodule.speek(rand, n, mixer)

It's up to you to decide.

Laurent LAPORTE
  • 21,958
  • 6
  • 58
  • 103
0

Firstly create a dict object with the key as tuple of string you want to match in your message and associate it with the value string which your Jarvis is suppose to respond. For example:

jarvis_dict = {
    ('goodbye',)  : ['Goodbye Sir', 'Jarvis powering off in 3, 2, 1, 0'],
    ('hello', 
     'hi')        : ['Wellcome to Jarvis virtual intelligence project. At your service sir.'],
    ('thanks', 
     'tanks', 
     'thank you') : ['You are wellcome', 'no problem'],
    ('jarvis',)   : ['Yes Sir?', 'What can I doo for you sir?'],
    ('how are you', 
     'and you', 
     'are you okay'): ['Fine thank you'],
    ('*',)        : ['Be polite please'],
    ('your name',): ['My name is Jarvis, at your service sir']
}

Now iterate each key of you dict to check whether any sub-string is the part of the message and if there is any match, call the speekmodule.speek(rand,n,mixer) function as:

for key, value in jarvis_dict.items():
    if any(item in message for item in key):
        speekmodule.speek(value, n, mixer)

Note: Here I am assuming that speekmodule.speek(value, n, mixer) in your code is working as there is no information available in your code regarding there declaration. I just replaced your rand with value as it the same list of str returned by the dict which is used in your code.

Moinuddin Quadri
  • 46,825
  • 13
  • 96
  • 126
  • You probably would like to use `random.choice(value)` to get random answer from a set of predefined variants. – skovorodkin Oct 02 '16 at 12:14
  • 2
    As I already mentioned in the answer, that I am not sure how `speekmodule.speek()` function behaves, and I am assuming that this function in the OP is working fine (and `random.choice(value)` is called internally by the `.speek()` function). My code is intended to provide the same functionality as the OP. – Moinuddin Quadri Oct 02 '16 at 12:18
0

Use dictionary:

someCollections = {
    'goodbye': "Something1",
    'hello': "Somthing2",
    ...
}

speekmodule(someCollections [SomeKey],...)
David
  • 15,894
  • 22
  • 55
  • 66