How to prevent random function printing the same row more than once from xslx file in python
Question:
So I’m a python beginner and don’t really know the gist of random functions. The following is my code (but only partially so it may not make sense but it has the point of what I wanted to ask. I put the conclusion of my code on the beginning of the paragraph after the code though. P.S. the code works):
if (1 <= numb_quiz <= 100):
from openpyxl import Workbook, load_workbook
book = load_workbook('Quiz_Problems.xlsx')
read_sheet = book['100 Questions']
length_row = read_sheet.max_row
sheet = book.active
numb_question = 1
point = 0
engagement = 0
correct = 0
while numb_question <= numb_quiz:
randrow = random.randint(2, length_row)
for row in read_sheet.iter_rows(randrow, randrow, min_col = 2, max_col = 2):
print("")
print("Question number", str(numb_question) + ":")
print([cell.value for cell in row])
for col in read_sheet.iter_rows(min_row = randrow, max_row = randrow, min_col = 3, max_col = 3):
print([cell.value for cell in col])
break
guest_answer = str(input("answer: "))
answer = str("D"+str(randrow))
correct_ans = sheet[answer].value
As you can see, to conclude what I wanted to do with the code above is to print random rows in column 3 with the random function from xslx file using python. The thing is, I wanted to prevent the random function to print the row from column 3 more than once in one run. Since again, I don’t really understand what the ‘import random’ library can actually do, perhaps there is a way to get what I wanted. Does anyone have a solution? thank you so much
P.S. Since I’m a python beginner, I also would fancy an explanation from you (so not just the code. thank you!)
Answers:
So random just generates a number in that range you want. Computers don’t generate numbers totally randomly. They use a "seed" to get started. If you pass the library the same seed each time (set it via random.seed(seedNo)), it will generate the same numbers in the same order. This can be useful for testing but also defeat the purpose of generating numbers. Therefore, a common practice is getting the current time of the system and using that as the seed.
Now for making sure you don’t get the same question printed twice, I recommend you create a new empty list and each time you get a question, you add that index to the list. Then, put in a conditional checking if the index has come up before, and if it has, just pass (move on to the next iteration of the loop). The code might look like this:
askedAlready = []
while numb_question <= numb_quiz:
randrow = random.randint(2, length_row)
if randrow in askedAlready: continue
for row in read_sheet.iter_rows(randrow, randrow, min_col = 2, max_col = 2):
print("")
print("Question number", str(numb_question) + ":")
print([cell.value for cell in row])
for col in read_sheet.iter_rows(min_row = randrow, max_row = randrow, min_col = 3, max_col = 3):
print([cell.value for cell in col])
break
guest_answer = str(input("answer: "))
answer = str("D"+str(randrow))
correct_ans = sheet[answer].value
askedAlready.append(randrow)
You could also rethink how you make the random generation. Make a list of all the possible question numbers then shuffle it. It won’t have any duplicates. Then you could just iterate through the shuffled list. Note that this also uses the seeding concept in the same way (random.seed())
(Inspired by thefourtheye’s answer: Generate 'n' unique random numbers within a range)
listOfRandRows = list(range(2,length_row))
random.shuffle(listOfRandRows) #this will shuffle the list "in place"
#then iterate
for i in listOfRandRows:
#do your thing. i will be the row number randomly chosen
Edit per pjs’s recommendation: shuffling is efficient enough but rejection can take a lot of extra time. Sample is better than rejection. It’s described here: Generate 'n' unique random numbers within a range under Two-Bit Alchemist’s answer
So I’m a python beginner and don’t really know the gist of random functions. The following is my code (but only partially so it may not make sense but it has the point of what I wanted to ask. I put the conclusion of my code on the beginning of the paragraph after the code though. P.S. the code works):
if (1 <= numb_quiz <= 100):
from openpyxl import Workbook, load_workbook
book = load_workbook('Quiz_Problems.xlsx')
read_sheet = book['100 Questions']
length_row = read_sheet.max_row
sheet = book.active
numb_question = 1
point = 0
engagement = 0
correct = 0
while numb_question <= numb_quiz:
randrow = random.randint(2, length_row)
for row in read_sheet.iter_rows(randrow, randrow, min_col = 2, max_col = 2):
print("")
print("Question number", str(numb_question) + ":")
print([cell.value for cell in row])
for col in read_sheet.iter_rows(min_row = randrow, max_row = randrow, min_col = 3, max_col = 3):
print([cell.value for cell in col])
break
guest_answer = str(input("answer: "))
answer = str("D"+str(randrow))
correct_ans = sheet[answer].value
As you can see, to conclude what I wanted to do with the code above is to print random rows in column 3 with the random function from xslx file using python. The thing is, I wanted to prevent the random function to print the row from column 3 more than once in one run. Since again, I don’t really understand what the ‘import random’ library can actually do, perhaps there is a way to get what I wanted. Does anyone have a solution? thank you so much
P.S. Since I’m a python beginner, I also would fancy an explanation from you (so not just the code. thank you!)
So random just generates a number in that range you want. Computers don’t generate numbers totally randomly. They use a "seed" to get started. If you pass the library the same seed each time (set it via random.seed(seedNo)), it will generate the same numbers in the same order. This can be useful for testing but also defeat the purpose of generating numbers. Therefore, a common practice is getting the current time of the system and using that as the seed.
Now for making sure you don’t get the same question printed twice, I recommend you create a new empty list and each time you get a question, you add that index to the list. Then, put in a conditional checking if the index has come up before, and if it has, just pass (move on to the next iteration of the loop). The code might look like this:
askedAlready = []
while numb_question <= numb_quiz:
randrow = random.randint(2, length_row)
if randrow in askedAlready: continue
for row in read_sheet.iter_rows(randrow, randrow, min_col = 2, max_col = 2):
print("")
print("Question number", str(numb_question) + ":")
print([cell.value for cell in row])
for col in read_sheet.iter_rows(min_row = randrow, max_row = randrow, min_col = 3, max_col = 3):
print([cell.value for cell in col])
break
guest_answer = str(input("answer: "))
answer = str("D"+str(randrow))
correct_ans = sheet[answer].value
askedAlready.append(randrow)
You could also rethink how you make the random generation. Make a list of all the possible question numbers then shuffle it. It won’t have any duplicates. Then you could just iterate through the shuffled list. Note that this also uses the seeding concept in the same way (random.seed())
(Inspired by thefourtheye’s answer: Generate 'n' unique random numbers within a range)
listOfRandRows = list(range(2,length_row))
random.shuffle(listOfRandRows) #this will shuffle the list "in place"
#then iterate
for i in listOfRandRows:
#do your thing. i will be the row number randomly chosen
Edit per pjs’s recommendation: shuffling is efficient enough but rejection can take a lot of extra time. Sample is better than rejection. It’s described here: Generate 'n' unique random numbers within a range under Two-Bit Alchemist’s answer