Python Forum
Index error using pop in nested loop - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: Index error using pop in nested loop (/thread-17085.html)



Index error using pop in nested loop - PerksPlus - Mar-27-2019

Hello. This is my first post, so I hope I'm not screwing this up too badly. I'm trying to get back into Python and coding in general after a 10ish year hiatus by making a snake game.

I'm creating a list of directions and a list of wait times for each snake body segment. When wait is 0 the snake body segments update their direction according accompanying list of directions. This works as intended until I attempt to clear the lists of unnecessary data by calling pop(). I'm assuming what's happening is because the list is being popped during the loop, the next iteration doesn't have the correct ranges, but I can't think of a clean alternative way to clean the list of used data.

Any insight would be appreciated. Thank you!

    def change_direction(self, new_direction):
        if new_direction != self.snake_head.direction:
            self.snake_head.direction = new_direction
            for i in range(len(self.snake_body)):
                self.snake_body[i].wait.append(i+1)
                self.snake_body[i].directions.append(new_direction)

    def traffic_control(self):
        for x in range(len(self.snake_body)):
            for y in range(len(self.snake_body[x].wait)):
                self.snake_body[x].wait[y] -= 1
                if self.snake_body[x].wait[y] == 0:
                    self.snake_body[x].change_direction_body(self.snake_body[x].directions[y])
                    #list.pop(self.snake_body[x].wait, y)
                    #list.pop(self.snake_body[x].directions, y)



RE: Index error using pop in nested loop - ichabod801 - Mar-27-2019

First, you should loop directly over things, not over their indexes:

def traffic_control(self):
    for segment in self.snake_body:
        for timer in segement.wait:
            ...
Second, you just don't want to mess with a list while iterating over it. I think the best solution would be to build a new list. So start with new_body = [], and then if you want to keep it, new_body.append(segment).


RE: Index error using pop in nested loop - PerksPlus - Mar-28-2019

Thanks for the reply. I attempted to swap around some of my code to fit that convention of just iterating through the objects themselves, but I think I made some structural errors in how my program fits together and I'm not sure if the situation can be salvaged. In the example above, I can't get around needing the index to retrieve the specific directions for the snake body. I tried an enumeration as a kind of hack, but that failed and I'm not quite sure why.
    def traffic_control(self):
        for segment in self.snake_body:
            for index, timer in enumerate(segment.wait):
                timer -= 1
                if timer == 0:
                    segment.change_direction_body(segment.directions[index])
I did manage to find a really hacky way to clear the used data from my lists, but I'm really not happy with it. I again couldn't find an alternative to using indexes as a way to sort through the data that needed cleaning, so this is what the function ended up looking like. I hope this isn't too painful to look at.

    def traffic_control(self):
        dirtyx = []
        dirtyy = []
        for x in range(len(self.snake_body)):
            for y in range(len(self.snake_body[x].wait)):
                self.snake_body[x].wait[y] -= 1
                if self.snake_body[x].wait[y] == 0:
                    self.snake_body[x].change_direction_body(self.snake_body[x].directions[y])
                    dirtyx.append(x)
                    dirtyy.append(y)
        for item in range(len(dirtyx)):
            list.pop(self.snake_body[dirtyx[item]].wait, dirtyy[item])
            list.pop(self.snake_body[dirtyx[item]].directions, dirtyy[item])



RE: Index error using pop in nested loop - ichabod801 - Mar-28-2019

I was thinking something more like this:

def traffic_control(self):
    for segment self.snake_body:
        new_wait, new_directions = [], []
        for timer, direction in zip(segment.wait, segment.directions):
            timer -= 1
            if timer:
                new_wait.append(timer)
                new_directions.append(direction)
            else:
                segment.change_direction_body(direction)
        segment.wait = new_wait
        segment.directions = new_directions
I think that should work and is a lot cleaner. I would also think about the underlying data structures. Can they be redesigned to work more smoothly with what needs to be done to them?