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