I think I did the project correctly even though the test for the experiment function fails.
In Replit I always get 0.293, which fails due to their expected outcome of 0.272. When I run the exact code in Jupyter Notebook, sometimes I get the number very close to 0.272, sometimes an exact match. I get a range of numbers from approximately 0.260-0.294. Which to me makes sense, since drawing at random will not yield the same results everytime(like the project ReadMe notes). I’m open to suggestions for anything I may have missed or improvements to code.
Code:
import copy
import random
# Consider using the modules imported above.
class Hat:
def __init__(self,**kwargs):
self.kwargs = kwargs
self.contents = []
for key,value in self.kwargs.items():
for i in range(0,value):
self.contents.append(key)
def draw(self, num_balls):
self.content_copy = self.contents.copy()
if num_balls > len(self.contents):
return(self.contents)
else:
draws = []
for x in range(num_balls):
draws.append(self.contents.pop(random.randrange(len(self.contents))))
return(draws)
def experiment(hat, expected_balls, num_balls_drawn, num_experiments):
#track the number of times an experiment resulted in having all the expected balls drawn
count = 0
for x in range(0,num_experiments):
#set up empty dictionary to track balls that are drawn
drawn = {}
placeholder = copy.deepcopy(expected_balls)
draw = hat.draw(num_balls_drawn)
hat.contents = hat.content_copy
#iterate through the drawn balls list and store the number of times drawn in drawn dictionary
for y in draw:
if y in drawn:
drawn[y] += 1
else:
drawn[y] = 1
#iterate through the keys of drawn, check if the value in drawn is equal to or greater than the amount in placeholder
for i in list(placeholder.keys()):
#if the amount drawn for the color is
if i in drawn:
if drawn[i] >= placeholder[i]:
placeholder[i] = True
else:
placeholder[i] = False
else:
continue
if set(list(placeholder.values())) == {True}:
count += 1
else:
continue
return(count/num_experiments)
Tests are using specific seed number, to ensure random values from random module are repeatable during testing and therefore it’s possible to test if result is as expected. This means, with the seed number used in testing function returned 0.293, while expected answer is 0.272.
I haven’t looked enough at the code, to be sure where is the problem, but often there are discrepancies between specification and how draw method is handling some edge cases (ie. when number of balls to draw is higher than number of balls in hat).
The placeholder is to keep track of how the drawn balls compare to expected_balls, without changing the original contents of expected_balls.
I set the hat.contents to the hat.content_copy after the draw to restore the contents to the original state, for the next experiment. Before I added this code, I noticed the contents were different in each experiment, due to the draw function removing the object drawn from the contents list.
I believe I accounted for the edge case in my draw method. It simply returns all the contents if the number of balls to draw is greater than the number of items in contents.
There’s no need to assign kwargs as an instance attribute when it’s never used outside of __init__()
There’s no need to specify 0 as the start for range(), it’s the default
As stated above, change+restore would be better accomplished by making a (deep) copy of hat
When not actually using the iteration variable, replace it with an underscore _ to make that clear
dict.keys() can be iterated over directly, no need to convert to a list first
if set(list(placeholder.values())) == {True}:
This line is probably the source of your test failure. My guess is that because 0 == False and 1 == True in Python, something like {1, True} is being evaluated as equal to {True}, causing a false positive.
Thank you all for the suggestions! You have truly been helpful and the project is now officially done. I have incorporated some of the changes you have suggested.
-copied the entire hat object and drew from copied hat
-used “_” when not using iteration variable if set(list(placeholder.values())) == {True}:
was setting off false positives when I ran a debug. great catch.
I ended up replacing the True with “Yes” and False with “No” instead. That took care of the false positives.