-2

I have a simple python program.

from nltk.tokenize import word_tokenize

negation ='no','not','never'.split(',')
list2 = 'miss,loss,gone,give up,lost'.split(',')
sentence = 'loss money'

if any(word in list2 for word in word_tokenize(sentence)) and (any(word in     
list2 for word in word_tokenize(sentence))[-1:])not in negation :
  print 'sad'
else:
  print 'not sad'

This make error which is

TypeError: 'bool' object has no attribute '__getitem__'

What I need here, I want to check if any word in the sentence is in the list2. If yes, then want to check its before index value is in the negation list or not. if yes it should be "not sad".

For an example "I miss him" should sad, "I not miss him" should be not sad.

Can anyone help me !

Chathuri Fernando
  • 950
  • 3
  • 11
  • 22

2 Answers2

3

You have a number of problems here, for starters:

  • If you are going to be looking through sets of words, use sets, not lists. e.g. negations={'no','not','never'}
  • 'give up' will never be found as a token in a sentence.
  • any() returns a boolean (see this question) for how it works.
  • listobj[-1:] returns the slice of the list with only the last element
  • you are not trying to extract items from a list or container, as any() returns a boolean, you are trying to treat a boolean as a container. This is what is causing the error you can see.

I suggest you break down your problem into more logical steps rather than jumping straight into list comprehensions / generators.
Where you want to access items in a list based on the position of others, I recommend starting with a indexed for loop:

for index, value in enumerate(var):
    last_word=var[index-1] if index > 0 else None

And do operations like word tokenisation only once, no need to keep doing it over and over.

Example solution:

def sad_sentence(sentence):
    wordlist=sentence.split()
    negations={'no','not','never'}
    negphrases={'miss','loss','gone','give up','lost'}

    for index, word in enumerate(wordlist):
        last_word=wordlist[index-1] if index > 0 else None
        if word in negphrases:
            if last_word in negations:
                print 'not sad'
            else:
                print 'sad'
            break;
        print 'not sad'

This results in:

>>> sad_sentence("I am not gone")
not sad
>>> sad_sentence("I am not here I am gone")
sad
>>>
Baldrickk
  • 4,291
  • 1
  • 15
  • 27
2

You didn't write the second part of your if well. You first look at any(word in list2 for word in word_tokenize(sentence)) which returns a boolean. Then you try to extract the last element of this boolean ([-1]) which return an error.

No need to use nltk library here, you can do it with just .split():

negation ='no,not,never'.split(',')
list2 = 'miss,loss,gone,give up,lost'.split(',')

def f(sentence):
    if any(word in list2 for word in sentence.split()) and not any(word in negation for word in sentence.split()):
        print 'sad'
    else:
        print 'not sad'

l = ['loss money', 'I miss him', 'I not miss him']
for e in l:
    f(e)
# Outputs: sad / sad / not sad

edit New version to take into account @Baldrickk good remark. I took two more cases into consideration. It prints 'happy' if no words belong to list2. If several words belongs to list2, it checks every previous words and not just the first one.

negation = {'no', 'not', 'never'}
list2 = {'miss', 'loss', 'gone', 'give up', 'lost'}

def f(sentence):
    s = sentence.split()
    l = [s.index(word) for word in s if word in list2]
    # Will returns list of indices (of sentence) where word is in list2
    if len(l) > 0:
        for e in l:
            # Check previous word
            if s[e-1] not in negation:
                print 'sad'
            else:
                print 'not sad'
    else:
        print 'happy'

l = ['loss money', 'I miss him', 'I not miss him', 'happy new year', 'I am not here I am gone']
for e in l:
    f(e)
# sad / sad / not sad / happy / sad
Nuageux
  • 1,668
  • 1
  • 17
  • 29
  • note, you are not looking for the preceding word when a match to list2 is found, just for a negation to be present. "I am not here I am gone" would return `"not sad"` with your code, when the described algorithm would return `"sad"` – Baldrickk Jun 07 '17 at 09:56
  • @Baldrickk Thanks for your comment, I didn't notice! I updated to fix this issue :) – Nuageux Jun 07 '17 at 10:02
  • Nice, this is exactly what I expected. Thank you. – Chathuri Fernando Jun 07 '17 at 10:53
  • @Nuageux Can I use this function within a Lambda Expression? – Chathuri Fernando Jun 07 '17 at 11:05
  • new version is nice, I do like the finding the indexes, that's quite smart. Of course it breaks on input like: `'miss him? happy I am not'` (this comes back `'not sad'` when like my solution, it should be `'sad'`.) I'll leave the _why_ it breaks to you. – Baldrickk Jun 07 '17 at 11:05
  • Is it possible to write this function inside a lambda expression? – Chathuri Fernando Jun 07 '17 at 11:11
  • @Baldrickk I knew I should have left the exception for the *Yoda* style case. If `e==0` then I should always print 'not sad'. – Nuageux Jun 07 '17 at 11:12
  • if `e==0` then you want `'sad'` according to the question. he isn't looking for `'sad I am not'` to be `'not sad'` as my erronous input example shows, you would need to understand the whole line to interpret meaning if you mean to do that.( `'sad I am not'` is happy and `'sad I am, happy I am not'` is sad) – Baldrickk Jun 07 '17 at 11:14