Tomato-Cumber
Tomato-Cumber

Reputation: 3

whats wrong with this while loop in Python?

Ok so I have spent hours trying to resolve this and I feel its some simple error but I cannot find a way to resolve this. the section I am having issues with is the second half of the code. There seems to be an infinite loop somewhere among the 2 nested while loops. If anyone is able to help, this would be great, thanks in advance.

import sympy as sym
import random

A, B, C, D, E, F, G, H, I, J = sym.symbols('A, B, C, D, E, F, G, H, I, J')
picks_a_person = [A, B, C, D, E, F, G, H, I, J] #List of people picking a name from a hat
person_gets_picked = [A, B, C, D, E, F, G, H, I, J] # List of names drawn from a hat
def re_draws(p):
    n = 0
    count = 0
    while n < 1000: #Repeats the test 1000 times for an accurate percentage
        n += 1
        random.shuffle(person_gets_picked) #Chooses a random order of the list of names drawn
        for i in range(p):
            if person_gets_picked[i] == picks_a_person[i]: #Checks for all 'p' elements of the lists are different
                count = count + 1
    print("count = " + str(count)) #Returns the number of times a re-draw was not required

import numpy as np
from collections import Counter

total = []
while len(total) < 1000:
    order = []
    picks_a_person = [A, B, C, D, E, F, G, H, I, J]
    person_gets_picked = [A, B, C, D, E, F, G, H, I, J]
    while len(order) < 10:
        a = person_gets_picked[random.randint(0, (len(person_gets_picked)-1))]
        if a != picks_a_person[0]:
            order.append(a)
            person_gets_picked.remove(a)
            del picks_a_person[0]
    total.append(order)
Counter(np.array(total)[:,1])

Upvotes: 0

Views: 49

Answers (1)

zwer
zwer

Reputation: 25779

While there are a lot of odd things about your code, this is where it gets into an infinite loop:

picks_a_person = [A, B, C, D, E, F, G, H, I, J]
person_gets_picked = [A, B, C, D, E, F, G, H, I, J]
while len(order) < 10:
    a = person_gets_picked[random.randint(0, (len(person_gets_picked)-1))]
    if a != picks_a_person[0]:
        order.append(a)
        person_gets_picked.remove(a)
        del picks_a_person[0]
total.append(order)

Let's do some rubber duck debugging - what happens when your random.randint(0, (len(person_gets_picked)-1)) returns a number larger than 0 nine times in a row (worst case scenario)? All person_gets_picked elements except A get removed and added to the order list (which is still under 10 elements to break away from the while loop).

At that point we have a state as picks_a_person = [A] and person_gets_picked = [A]. random.randint(0, (len(person_gets_picked)-1)) will, thus, always return 0, a will always be set to A and since picks_a_person[0] == A the condition if a != picks_a_person[0] will never be evaluated as True, hence the order will never get its 10th element and therefore you got yourself an infinite loop.

It doesn't even have to be nine positive numbers in a row for this to occur - all it needs to happen is for A to remain as one of the last two picks and for random to land on the other option.

So why don't you write your whole loop as:

persons = [A, B, C, D, E, F, G, H, I, J]
persons_num = len(persons)
total = [random.sample(persons, persons_num) for _ in range(1000)]

And you're done.

Upvotes: 2

Related Questions