-1

Im currently working on this code, that supposed to remove words that starts with 'no' this is what i have written so far.

text='none none is here but none is coming here again'

def count_words(text):
    sent=text.split(" ")
    for i in range(len(sent)):
        if sent[i][0]=='n' and sent[i][1]=='o':
            sent.remove(sent[i])
              
    return sent

But when running i meet this error message: IndexError: list index out of range. Im not sure where im going out of range, anyone who can see that?

Brokhus
  • 9
  • 1
  • 2
    Every time you call `sent.remove`, the largest valid index decreases by one. But the range you are iterating over doesn't. – chepner Jan 20 '21 at 22:23
  • Are you trying to remove all "none" from the text, if so there are much better ways to do it – Jakov Gl. Jan 20 '21 at 22:25
  • Does this answer your question? [How to remove items from a list while iterating?](https://stackoverflow.com/questions/1207406/how-to-remove-items-from-a-list-while-iterating) – Tomerikoo Jan 20 '21 at 22:39

5 Answers5

2

after your remove the length is shorter. Typically, do range(len(sent)-1,-1,-1) to traverse from the end, or make a copy of the list to work with

Bing Wang
  • 1,548
  • 1
  • 8
  • 7
  • Ahh that makes sense, hadnt thought about that! It works perfectly with -1,-1,-1. But when trying to make a copy its still suffers the same issue.. still same error message.. ive used placeholder=sent.copy() – Brokhus Jan 20 '21 at 22:41
  • print(' '.join(filter(lambda x: not x.startswith('no'), text.split()))) – Bing Wang Jan 21 '21 at 00:56
2

As mentioned in the comments, the index gets smaller every time you remove an element

You can solve that issue some way, but there's a somewhat more Pythonic approach to the problem, as seen below:

text='none none is here but none is coming here again'

def count_words(text):
    sent=text.split(" ")
    words = []
    for word in sent:
        if not word.startswith("no"):
            words.append(word)
            
    return ' '.join(words)

print(count_words(text))

Short primer if you're unfamiliar:

  • Accumulate the words you want in a list: words
  • Use the comparison method String.startswith to look for the relevant words
  • If the word didn't start with 'no', then add it to your accumulator
  • Finally join the message with the spaces we previously split by, using String.join
kluvin
  • 5,235
  • 3
  • 13
  • 20
1

Thats because in each loop where condition "no" is valid, you shrink your sent array but loop is still referencing to original sent length.

You can check it by add print(sent) in for loop.

But you don;t have to do so much complicated logic to this kind of simple task.

sent = text.split(" ")
for word in sent:
    if len(word) >= 2 and word[0:2] == "no":
        sent.remove(word)
return " ".join(sent)

this code will do the same

Michael Stachura
  • 1,100
  • 13
  • 18
1

Your code is almost correct, I have done a minor change;

text = 'none none is here but none is coming here again'
def count_words(text):
    sent = text.split(" ") # ['none', 'none', 'is', 'here', 'but', 'none', 'is', 'coming', 'here', 'again']
    for chunk in sent:
        if chunk[0] == 'n' and chunk[1] == 'o': # if chunk.startswith('n')
            sent.remove(chunk)
    return sent
print(count_words(text))
    
['is', 'here', 'but', 'none', 'is', 'coming', 'here', 'again'] # is here but none is coming here again
nectarBee
  • 401
  • 3
  • 9
0

For Splitting if you are not sure about no of index data may have then we have an option to specify maximum number of delimiter split should consider, remaining data will be loaded over last element as :- string.split(separator,max)

New code will be as given below

text = 'none none is here but none is coming here again'
def count_words(text):
    return [chunk for chunk in text.split(" ", 4) if not chunk.startswith("no")]
print(count_words(text))

Output : --> ['is', 'here', 'but none is coming here again']

We can tweak value of maximum element as per our requirements.

Vibhor Gupta
  • 670
  • 7
  • 16