-2

I am working on a Python project that turns your speech into words then puts it into a Google Sheet. This is some of the logic and it is not quite working...

text = "First and 10 gain of 10 yards"
words = text.lower().split()
length = len(words)

print(words)

i = 0

for i in range(length):
    print(i)

    if words[i] == 'and':
        words[i] = '-'

    if words[i] == 'first':
        words[i] = '1'

for i in range(length):
    if words[i] == '-':
        words[i - 1 : i + 1] = [''.join(words[i - 1 : i + 1])]
        i = i + 1
        length = length - 1

print(words)

Here's the output:

['first', 'and', '10', 'gain', 'of', '10', 'yards']
0
1
2
3
4
5
6
Traceback (most recent call last):
  File "Testing.py", line 48, in <module>
    if words[i] == '-':
IndexError: list index out of range
wjandrea
  • 28,235
  • 9
  • 60
  • 81
  • Which line is line 48? I'll bet it's in the second for loop, not the first one. And that would mean your print statement isn't telling you where the error is happening. – The Photon Jan 16 '22 at 16:46
  • 2
    What is your desired output? – Jasmijn Jan 16 '22 at 16:48
  • @ThePhoton Yes, the traceback indicates the line: `if words[i] == '-':`, which is in the second loop. – wjandrea Jan 16 '22 at 16:57
  • 1
    Welcome to Stack Overflow! Please read about [How to debug small programs](http://ericlippert.com/2014/03/05/how-to-debug-small-programs/). You can also use [Python-Tutor](http://www.pythontutor.com/visualize.html#mode=edit) which helps to visualize the execution of the code step-by-step. – Tomerikoo Jan 16 '22 at 16:57
  • So why did you print the iteration index in the first loop and not the second? – The Photon Jan 16 '22 at 16:58
  • @ThePhoton Are you replying to me? I'm not OP. – wjandrea Jan 16 '22 at 16:58
  • Welcome to Stack Overflow! Please take the [tour]. For debugging help, you need to make a [mre] including expected output. Also note that both `i =` statements do nothing. You can [edit]. For more tips, see [ask]. I also agree with Tomerikoo: you'd benefit from learning how to do your own debugging. – wjandrea Jan 16 '22 at 17:09
  • this is because `words[i - 1 : i + 1]` ... there is no `i+1` when `i == length` – Flash Thunder Jan 16 '22 at 19:47

3 Answers3

0

The simple answer is that in your code:

for i in range(length):
    if words[i] == '-':
        words[i - 1 : i + 1] = [''.join(words[i - 1 : i + 1])]
        i = i + 1
        length = length - 1  

you are modifying the list of words which results in the loop running beyond the length of the list.

You can address this problem as follows:

ptr = 0
while ptr < len(words):
    if words[ptr] == '-':
        words[ptr-1:ptr+1] = [''.join(words[ptr -1: ptr+1])]
    ptr += 1

Output:

['1-', '10', 'gain', 'of', '10', 'yards']
wjandrea
  • 28,235
  • 9
  • 60
  • 81
itprorh66
  • 3,110
  • 4
  • 9
  • 21
  • 1
    @GrahamFreeman Just a small advice: the fact that it worked doesn't mean it should be used (no offence to the answerer). Your question is really not clear and you didn't even explain what it is you are actually trying to do. If you would do so, we might suggest a much simpler way to do it – Tomerikoo Jan 16 '22 at 17:08
  • @Graham Don't forget to [upvote answers you find useful and accept the best one](/help/someone-answers) :) Although I agree with Tomerikoo: there could be better answers. For example, maybe regex (`re.sub`) could be simpler. – wjandrea Jan 16 '22 at 17:13
0

You're changing the value of length assuming this will affect range(length) so the loop will run up to the new value of length - 1. But the problem is range(length) returns an inmutable sequence, so the loop will always run up to the value of length given at the start of the loop - 1. In other words, if the list is 7 elements in length, the loop will iterate 7 times regardless of your changes to the length variable.

Follow @itprorh66's suggestion.

  • Mutability has nothing to do with it. The problem is that the `expression_list` part of a [`for` statement](https://docs.python.org/3/reference/compound_stmts.html#the-for-statement) is evaluated once. I think that's what you meant, but you just have the mechanics a little confused :) – wjandrea Jan 16 '22 at 17:22
  • @wjandrea, ranges do not provide all the values at once, but calculate "individual items and subranges as needed." https://docs.python.org/3/library/stdtypes.html#ranges –  Jan 16 '22 at 17:31
  • @cesarv I'm aware of that. What I'm saying is, the cause of the problem is in the syntax, not the data. – wjandrea Jan 16 '22 at 17:34
  • @wjandrea, not really. Run this: `L = [1, 2, 3] (newline) for e in L: (newline) print(e) (newline) if e == 2: L.remove(3)`. It won't fail even though the `expression_list` part of the for statement is evaluated once. –  Jan 16 '22 at 17:50
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/241106/discussion-between-cesarv-and-wjandrea). –  Jan 16 '22 at 17:52
-1

The second time you use for i in range(length), you are setting i to be in the range from 0 to the length, however, this range is only calculated once and becomes an immutable sequence.

Then you modify the list with this line:

words[i - 1 : i + 1] = [''.join(words[i - 1 : i + 1])]

this is shortening the list and i ends up bigger than the index.

If you change the logic around the second for loop to:

i = 0
while i < length:
    if words[i] == '-':
        words[i - 1 : i + 1] = [''.join(words[i - 1 : i + 1])]
        length = length - 1
    i = i + 1
    

It will work.

jgritty
  • 11,660
  • 3
  • 38
  • 60
  • 1
    That is simply not true. The line `i = i + 1` has no effect whatsoever... (same for the line `length = length - 1` for that matter) – Tomerikoo Jan 16 '22 at 16:55