Функция Python, которая возвращает значение в определенный процент времени - PullRequest
0 голосов
/ 03 октября 2018

Во время интервью мне дали следующий кодовый вопрос, который я не смог понять.С тех пор я думал об этом и не могу понять, как написать функцию, которая возвращает значение для заданного процента времени.

Вопрос состоит в следующем:

Скажем, у вас есть словарь dict = {'A': 10, 'B': 30, 'C': 60}.Напишите функцию, которая возвращает «A» в 10% случаев, «B» в 30% случаев и «C» в 60% случаев.Таким образом, функция должна принимать словарь со значениями в виде чисел (они не обязательно должны добавлять до 100), и она должна возвращать ключ этого значения в соответствии с процентным отношением этого ключа к сумме всех ключей.

У меня есть идея, как запустить функцию ...

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

Я новичок в Python, поэтому, пожалуйста, извините за мое невежество и спасибо заваша помощь!

Ответы [ 4 ]

0 голосов
/ 03 октября 2018

`random.choices * принимает взвешенное распределение, не уверенный, если цель состоит в том, чтобы напечатать или сохранить в счетчике, но любой из них может быть сделан таким образом

from random import choices
d = {'A': 10, 'B': 30, 'C': 60}
l = []
for i in range(sum([v for v in d.values()])):
    l.append(*choices([k for k in d],[.1, .3, .6]))

print(l)
print({i: l.count(i) for i in [k for k in d]})
['C', 'C', 'B', 'C', 'C', 'C', 'C',..., 'C', 'C', 'B']
{'A': 8, 'B': 30, 'C': 62}
0 голосов
/ 03 октября 2018

Вы можете использовать random.randrange, чтобы нарисовать значение между 0 и суммой всех значений dict, используйте itertools.accumulate, чтобы сгенерировать последовательность кумулятивных сумм из значений, а затем используйте itertools.dropwhile, чтобы найти первый совокупныйсумма, которая не меньше, чем ничья, и верните ключ dict по этому индексу, сопровождаемый кумулятивной суммой с использованием 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]]

, так что:

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

может выводить:

Counter({'C': 587, 'B': 286, 'A': 127})
0 голосов
/ 03 октября 2018

Может ли это быть?... Я не уверен, что понял вопрос, хотя мой код будет распечатывать каждый ключ в зависимости от их "шанса".

from random import randint

example = {
    'A': 10,
    'B': 50,
    'C': 80
}

def percent_return(dictionary):
    for key, value in dictionary.items():
        if randint(1, 100) < value:
            yield key

for char in percent_return(example):
    print(char)
0 голосов
/ 03 октября 2018

Есть несколько проблем с вашим кодом:

  1. Вы скрываете встроенные sum и dict.Никогда не делайте этого.
  2. Вы правильно рассчитали массив процентов, но не связали их с ключами.
  3. Нет логики для получения взвешенной выборки из ваших ключей.

Встроенный random.choice уже имеет эту функцию.Для эффективности вы можете использовать sum непосредственно с dict.values и использовать словарь для вычисления весов.Поскольку random.choices возвращает список, мы можем использовать next с iter для извлечения единственного элемента.

from random import choices

d_weights = {'A': 10, 'B': 30, 'C': 60}

def percent_return(d):
    val_sum = sum(d.values())
    d_pct = {k: v/val_sum for k, v in d.items()}
    return next(iter(choices(population=list(d_pct), weights=d_pct.values(), k=1)))

res = percent_return(d_weights)
...