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)):
...