AlanK
AlanK

Reputation: 9833

Test for an empty list comprehension in if/else statement

Is it possible to reduce the amount of lines in the method find_indexes to just 1 line using an if/else statement like as seen in the return statement?

def find_indexes(sentence, target):
    indexes = [index for index, x in enumerate(sentence.split()) if target == x]

    return indexes if indexes else False

target = 'dont'
sentence = 'we dont need no education we dont need no thought control no we dont'

print(find_indexes(sentence, target))
>> [1, 6, 13]
print(find_indexes(sentence, 'johndoe'))
>> False

I'm looking to change the method to something like this, without the need to write the comprehension twice:

def find_indexes(sentence, target):
    return [index for index, x in enumerate(sentence.split()) if target == x] \ 
       if [index for index, x in enumerate(sentence.split()) if target == x] else False

Write a procedure that takes a string of words separated by spaces (assume no punctuation or capitalization), together with a ”target” word, and shows the position of the target word in the string of words.

For example, if the string is:

we dont need no education we dont need no thought control no we dont

and the target is the word:

”dont”

then your procedure should return the list 1, 6, 13 because ”dont” appears at the 1st, 6th, and 13th position in the string. (We start counting positions of words in the string from 0.) Your procedure should return False if the target word doesn’t appear in the string

Upvotes: 1

Views: 2028

Answers (4)

Eric Duminil
Eric Duminil

Reputation: 54233

Returning False isn't only pointless, it makes the code larger and more brittle.

Every time you use the original find_indexes function, you need to check if it's a boolean or a list. Otherwise, your code might raise a TypeError if no index is found:

def find_indexes(sentence, target):
    indices = [index for index, x in enumerate(sentence.split()) if target == x]
    return indices if indices else False

sentence = 'we dont need no education we dont need no thought control no we dont'

for index in find_indexes(sentence, "not_found"):
    print(index)

It throws:

TypeError: 'bool' object is not iterable

As suggested by @chepner, simply return an empty list if no index is found : an empty list is falsey in Python anyway. You need one line less in your function and in every susequent call.

Finally, since Python is a dynamic language, it's really important to use adequate function names in order to write readable code. If your function is called find_indexes, it should return an iterable. If it's called is_a_substring, then it should return a boolean.

Upvotes: 1

chepner
chepner

Reputation: 531245

Just return the empty list if there are no matches found.

def find_indexes(sentence, target):
    return [index for index, x in enumerate(sentence.split()) if target == x]

indices = find_indexes("hi there bob", "bob")
if not indices:
    print("No matches found")
else:
    for i in indices:
        print("Found match at {}".format(i))

Upvotes: 4

Moses Koledoye
Moses Koledoye

Reputation: 78556

You can short-circuit with or:

def find_indexes(sentence, target):
    return [i for i, x in enumerate(sentence.split()) if target == x] or False

Upvotes: 3

deceze
deceze

Reputation: 522135

return [...] or False

The or operator returns one of its operands; the first if the first is truthy, otherwise the second.

Upvotes: 3

Related Questions