Home > Back-end >  If statement in for loop, index out of range with one additional condition?
If statement in for loop, index out of range with one additional condition?

Time:11-17

I'm trying to create an if statement in a for loop to look at an element in a list and compare it to the next element with enumerate().

arr = ["NORTH", "SOUTH", "SOUTH", "EAST", "WEST", "NORTH", "WEST"]
liste = []
for idx,i in enumerate(arr):
    if (i == 'NORTH' and arr[idx 1] == 'SOUTH') or (i == 'SOUTH' and arr[idx 1] == 'NORTH') or (i == 'EAST' and arr[idx 1] == 'WEST') or (i == 'WEST' and arr[idx 1] == 'EAST'):
        liste.append(idx)
        liste.append(idx 1)
print(liste)

expected

[0, 1, 3, 4]

got

---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
Input In [44], in <cell line: 2>()
      1 liste = []
      2 for idx,i in enumerate(arr):
----> 3     if (i == 'NORTH' and arr[idx 1] == 'SOUTH') or (i == 'SOUTH' and arr[idx 1] == 'NORTH') or (i == 'EAST' and arr[idx 1] == 'WEST') or (i == 'WEST' and arr[idx 1] == 'EAST'):
      4         liste.append(idx)
      5         liste.append(idx 1)

IndexError: list index out of range

but if the original if is (without the last "or")

for idx,i in enumerate(arr):
    if (i == 'NORTH' and arr[idx 1] == 'SOUTH') or (i == 'SOUTH' and arr[idx 1] == 'NORTH') or (i == 'EAST' and arr[idx 1] == 'WEST'):

it goes through fine and gives the expected outcome (this case has no reversed west/east anyway, but I of course want it to work for random lists).

What's up with that? It's a codewars problem and I can come up with a workaround myself, so I don't want the solution to the whole problem, I'm just trying to understand why it's behaving this way. EDIT: I just realized it's because the last element in the list is actually "WEST" so then it's checking idx 1 which for the last element is not in the list. In that case I would be interested in how to avoid that!

CodePudding user response:

When you reach your last element, idx 1 is out of bounds for the array. You would want to keep that in mind in your logic. One way to resolve is to enumerate over the length-1 of the array so it is never trying to access an index out of bounds.

For example:

arr = ["NORTH", "SOUTH", "SOUTH", "EAST", "WEST", "NORTH", "WEST"]
liste = []
for idx,i in enumerate(arr[:len(arr)-1]):
    if (i == 'NORTH' and arr[idx 1] == 'SOUTH') or (i == 'SOUTH' and arr[idx 1] == 'NORTH') or (i == 'EAST' and arr[idx 1] == 'WEST') or (i == 'WEST' and arr[idx 1] == 'EAST'):
        liste.append(idx)
        liste.append(idx 1)
print(liste)

outputs [0,1,3,4]

CodePudding user response:

When your loop arrives at the last element, it checks for 'WEST' and then tries to check the next element, but there is none. This gives the index error. A quick fix may be to append an element like 'END', for which none of the checks succeeds. Thus, no element past the end gets checked.

CodePudding user response:

The behavior you're describing is due to short-circuit evaluation. This condition:

i == 'WEST' and arr[idx 1] == 'EAST'

will check if i is equal to "WEST". Only when this check passes will it compare if arr[idx 1] is equal to "EAST" -- at which point an IndexError occurs. The other three conditions in your if statement behave analogously, which is why they don't cause an IndexError to occur.

You should create a slice so that you don't check past the last element:

from itertools import islice
for idx, i in enumerate(islice(arr, len(arr) - 1)):
    ...
  • Related