Search code examples
pythonlistfunctiondictionarysample

Python function that returns a value a certain percent of the time


During an interview, I was given the following coding question that I couldn't figure out. I've been thinking about it ever since then, and I can't seem to figure out how to write a function that returns a value for a given percent of the time.

The question goes as follows:

Say you have a dictionary dict = {'A': 10, 'B': 30, 'C': 60}. Write a function that returns 'A' 10% of the time, 'B' 30% of the time, and 'C' 60% of the time. So, the function should take in a dictionary with values as numbers (they don't necessarily have to add up to 100), and it should return that value's key in correspondence with the percentage that key is to the sum of all the keys.

I have an idea of how to start the function...

def percent_return(dict):
    sum = 0
    for key, value in dict.items():
        sum += float(value)
    percent_array = []
    for key, value in dict.items():
        percent = float(value) / sum
        percent_array.append(percent)
 ''' We now have an array with the associated percentages for the dictionary, 
but now I don't know how to actually apply this to the return values '''
    for key, value in dict.items():
        if (something that indicates given %):
            return key

I'm very new to python, so please excuse my ignorance and thanks for your help!


Solution

  • You can use random.randrange to draw a value between 0 and the sum of all dict values, use itertools.accumulate to generate a sequence of cumulative sums from the values, and then use itertools.dropwhile to look for the first cumulative sum that isn't less than the draw, and return the key of the dict at that index, as accompanied by the cumulative sum through the use of enumerate:

    import random
    from itertools import accumulate, dropwhile
    def pick(d):
        draw = random.randrange(sum(d.values()))
        return list(d.keys())[next(dropwhile(lambda t: t[1] < draw, enumerate(accumulate(d.values()))))[0]]
    

    so that:

    from collections import Counter
    d = {'A': 10, 'B': 30, 'C': 60}
    print(Counter(pick(d) for _ in range(1000)))
    

    can output:

    Counter({'C': 587, 'B': 286, 'A': 127})