1

I'm running into a funny scenario with list comprehensions and strings. Here's a simplified example of the scenario:

This:

banned = ['apple', 'pear']
sentence = 'I will eat an apple'    
if(not x in sentence for x in banned): print('ok')

Returns:

ok

Even though 'apple' appears in the sentence. Have I written the comprehension incorrectly? If any word in 'banned' is in 'sentence', 'ok' shouldn't print.

4
  • 1
    A non empty list (whatever the values) is truthy Commented Mar 27, 2017 at 16:52
  • 7
    you're after the all keyword - if all(not x in sentence for x in banned): print('ok') Commented Mar 27, 2017 at 16:52
  • 1
    it's a bit clearer if you use 'x not in sentence' Commented Mar 27, 2017 at 16:55
  • I'd probably use if not any(x in sentence for ...) instead of all(not x...), just makes more sense to me. Commented Mar 27, 2017 at 17:45

1 Answer 1

3

The following part:

(not x in sentence for x in banned)

Is a generator expression that will be evaluated as True, regardless of whatever the content is.

If you want to check the truth value of multiple items you may want to use either any or all functions based on your problem.

In this case it seems that you need all():

banned = ['apple', 'pear']
sentence = 'I will eat an apple'    
if all(x not in sentence for x in banned):
    print('ok')

Also, note that the part x not in sentence will check the membership within the entire string, not its words. That says, if one of the words within the input string is contain a word within banned list it will return True. Like pearl which is contain the word pear.

One way for getting around that problem is to check the membership in splitted text or use regular expressions.

Another alternative would be using set and intersection:

banned = {'apple', 'pear'}  # use set instead of list
sentence = 'I will eat an apple'
if banned.intersection(sentence.split()):
    print('ok')

As @Jean-FrançoisFabre mentioned it's better to use set.isdisjoint() rather than set.intersection since you just want to check the intersection.

banned = {'apple', 'pear'}  # use set instead of list
sentence = 'I will eat an apple'
if not banned.isdisjoint(sentence.split()):
    print('ok')
Sign up to request clarification or add additional context in comments.

4 Comments

if banned.intersection(sentence.split()): creates a set, which is wasteful. Better use not banned.isdisjoint() as a condition.
@Jean-FrançoisFabre isdisjoint() doesn't return a correct result for this problem. Try banned.isdisjoint('apple pear banana'.split()).
I wrote not {'apple', 'pear'}.isdisjoint('apple pear banana'.split()). not isdisjoint means intersection is not empty. That works.
@Jean-FrançoisFabre Ah, indeed it return True if two sets have a null intersection. Thanks for note though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.