0

I am trying to display a series of images randomly but I want to avoid repeating the images.

The code below works on startup but there comes a time when the following error simply appears:

pop index out of range

sufijos_png = list(range(1, 10+1))

def vars_for_template(self):
    n_img = random.choice(sufijos_png)
    self.player.n_loteria = n_img
    sufijos_png.pop(n_img-1)
    return dict(
        image_path='dict/G{}.png'.format(n_img)
    )´

Anyone have any idea how to fix this error?

1 Answers1

0

.pop() actually returns and removes the last element of the list sufijos_png, so with the logic above, it's possible that at some point it will try to remove the element at index n_img-1 from the list sufijos_png, which doesn't exist anymore. To demonstrate, let's take the example you gave:

sufijos_png = list(range(1, 10+1))
sufijos_png

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Notice that len(sufijos_png) = 10. Now, the first time we randomly choose a value from sufijos_png. Let's say that value is 9, so

n_img = random.choice(sufijos_png)
n_img
9

Then we pop (+ return) the value at position n_img-1 = 9-1 = 8 of sufijos_png.

sufijos_png.pop(n_img-1) # pops value at index position 8
sufijos_png
[1, 2, 3, 4, 5, 6, 7, 8, 10]

Now, imagine the next random draw from sufijos_png is equal to 10 (it's one of the values still remaining there). However, the length of sufijos_png is now 9, so the index range is 0-8. Therefore the following will raise an IndexError:

n_img = random.choice(sufijos_png)
n_img
10 # one of the remaining possible values in sufijos_png

sufijos_png.pop(n_img-1) # pops value at index position 10, which doesn't exist

IndexError: pop index out of range

One way to overcome this problem, assuming that you just need a random number that doesn't repeat itself to assign to self.player.n_loteria = n_img, is to generate a list of digits/values, then shuffle them, and then keep popping from this randomly ordered list. For example:

import random
sufijos_png = list(range(1, 10+1))
random.shuffle(sufijos_png) # just need to shuffle once

def vars_for_template(self):
    n_img = sufijos_png.pop() # every time you accessing, you're depleting the list
    self.player.n_loteria = n_img
    return dict(
        image_path='dict/G{}.png'.format(n_img)
    )
tania
  • 2,104
  • 10
  • 18