用Python方式将数字范围分配给存储桶

时间:2019-03-04 09:32:02

标签: python

我正在使用django开发ABtest框架。我想根据Cookie请求中的bucket_id分配变体编号。

bucket_id由前端设置,范围为0-99。

到目前为止,我已经创建了函数名称get_bucket_name:

def get_bucket_range(data):

    range_bucket = []
    first_val = 0
    next_val = 0

    for i, v in enumerate(data.split(",")):
        v = int(v)
        if i == 0:
            first_val = v
            range_bucket.append([0, first_val])
        elif i == 1:
            range_bucket.append([first_val, first_val + v])
            next_val = first_val + v
        else:
            range_bucket.append([next_val, next_val + v])
            next_val = next_val + v

    return range_bucket

get_bucket_range的数据输入是一个逗号分隔的字符串,这意味着我们有3个变体,每个变体都有自己的权重,例如data =“ 25,25,50”,第一个变体的权重为25等。

然后我创建了一个函数来分配名为

的变体
def assign_variant(range_bucket, num):
    for i in range(len(range_bucket)):
        if num in range(range_bucket[i][0], range_bucket[i][1]):
            return i

此函数应具有2个参数,分别是get_bucket_range函数的range_bucket->和cookie的num-> bucket_id。

使用此函数,我可以返回属于变体ID的bucket_id。

例如,我们将25作为bucket_id,数据=“ 25,25,50”。这意味着我们的bucket_id应该属于变体ID1。或者在我们将25作为bucket_id的情况下,数据=“ 10,10,10,70”。这应该意味着我们的bucket_id将属于变体ID 2。

但是,感觉我的函数都不是pythonic或没有优化的。这里有人对我如何改进代码有任何建议吗?

2 个答案:

答案 0 :(得分:1)

例如,您的函数可能如下所示:

def get_bucket_range(data):
    last = 0
    range_bucket = []
    for v in map(int, data.split(',')):
        range_bucket.append([last, last+v])
        last += v
    return range_bucket

def assign_variant(range_bucket, num):
    for i, (low, high) in enumerate(range_bucket):
        if low <= num < high:
            return i

答案 1 :(得分:1)

使用itertools.accumulatebisect.bisect函数可以大大减少函数的长度。第一个函数将所有权重求和(10,10,10,70变成10,20,30,100),第二个函数为您提供该元素所属位置的索引,在您的情况下,它等于组的索引它属于。

from itertools import accumulate
from bisect import bisect

def get_bucket_range(data):
    return list(accumulate(map(int, data.split(',')))

def assign_variant(range_bucket, num):
    return bisect(range_bucket, num)