Python 将数字拆分为可变速率计费的频带,即;“分层定价”;

Python 将数字拆分为可变速率计费的频带,即;“分层定价”;,python,algorithm,billing,Python,Algorithm,Billing,我有一个纸上很简单的问题,但我正努力用代码解决。在我进一步讨论之前,这不是一个拆分字符串的问题 我有一个基本上是带状时间表的应用程序。量表根据客户的不同而不同,但一个月的前三个小时是80小时,接下来的三个小时是70小时,其余的是50小时。我目前在代码中表示为: scale = [80, 80, 80, 70, 70, 70, 50] 。。。但我也愿意接受那里的建议 步骤的规模和数量是可变的,而且必须是可变的。我的一些账单对于一些客户来说要简单得多,但我希望能够提供这种高使用率计划 但我如何计算

我有一个纸上很简单的问题,但我正努力用代码解决。在我进一步讨论之前,这不是一个拆分字符串的问题

我有一个基本上是带状时间表的应用程序。量表根据客户的不同而不同,但一个月的前三个小时是80小时,接下来的三个小时是70小时,其余的是50小时。我目前在代码中表示为:

scale = [80, 80, 80, 70, 70, 70, 50]
。。。但我也愿意接受那里的建议

步骤的规模和数量是可变的,而且必须是可变的。我的一些账单对于一些客户来说要简单得多,但我希望能够提供这种高使用率计划

但我如何计算工作时间(如15.2小时)以及他们应该支付多少?我怎么把这个大数字分成几个乐队?正如我所说,在纸上工作很容易,但随着我有更多的客户和更复杂的计划,这就变得很无聊了。以下是我将如何计算15.2小时:

3 hours at 80 = 240
3 hours at 70 = 210
9.2 hours at 50 = 460
total = 910

当我在做这件事的时候,我非常感谢大家对我试图描述的东西的专有名称的评论。奥利,如果你在2023年回到这里,下次选择一个更简单的计费方案,伙计。

如果我正确理解这个问题,我会试试。它不紧凑,但我更喜欢可读性。我将bands表示形式更改为
[(小时,价格),(小时,价格),…(无,价格)]
,请参见下面的示例:

def calculate_cost(hours, bands):
    remaining_hours = hours
    current_band_idx = 0
    total_cost = 0

    while remaining_hours > 0:
        band_max_hours, band_cost = bands[current_band_idx]

        if band_max_hours is None:
            band_billable_hours = remaining_hours
        else:
            band_billable_hours = min(remaining_hours, band_max_hours)

        total_cost += band_billable_hours * band_cost
        current_band_idx += 1
        remaining_hours -= band_billable_hours

    return total_cost
举个例子:

>>> calculate_cost(15.2, [(3, 80), (3, 70), (None, 50)])
910.0

尽管在我的评论中,我建议采用最简单/最幼稚的方法,只是循环——我的好奇心战胜了我,因此这里有一个使用递归的“少行”方法

从“成本桶”列表开始,每个成本桶包含一组小时数的价格(例如,[3,80]=>3小时,以80个价格单位),您可以细分您的小时数,直到您按顺序填满每个成本桶(或到达“花费”所有剩余小时的最后一个成本桶)

#每个存储桶是一对[在此速率下的最大小时数,每小时速率]
def计算成本(成本桶:列表,工时):

如果你先工作小时,我会这样做:

scale = [80, 80, 80, 70, 70, 70, 50]
为此:

import math

scale = {(0, 3): 80, (3, 6): 70, (6, math.inf): 50}
然后,我的算法的其余部分如下所示:

# Total hours worked
hours_worked = 15.2

# Handle the decimal (if any) to begin with... First find the "max" rate
decimal_rate = next(rate for (lower, upper), rate in scale.items()
                        if lower <= hours_worked and upper >= hours_worked)

# Then calculate the last "sliver" of pay
decimal_end = hours_worked - int(hours_worked)
end_pay = decimal_end * decimal_rate

# Use an integer for ease of calculation
hours_worked = int(hours_worked)

hours_paid_for = 0

# Beginning total pay is just the decimal "ending"
total_pay = end_pay

while hours_paid_for < hours_worked:
    # Find the rate for the current bucket of hours
    rate_filter = (rate for (lower, upper), rate in scale.items() if lower <= hours_paid_for and hours_paid_for < upper)
    current_level = next(rate_filter)

    print('Hour: {}'.format(hours_paid_for))
    print('Pay rate: ${}'.format(current_level))

    total_pay += current_level

    hours_paid_for += 1

print('Total earned: ${}'.format(total_pay))
这里还有一个很好且简洁的函数:

def calculate_pay(scale, hours_worked):

    # Handle the decimal (if any) to begin with... First find the "max" rate
    decimal_rate = next(rate for (lower, upper), rate in scale.items()
                            if lower <= hours_worked and upper >= hours_worked)

    # Then calculate the last "sliver" of pay
    decimal_end = hours_worked - int(hours_worked)
    end_pay = decimal_end * decimal_rate

    # Use an integer for ease of calculation
    hours_worked = int(hours_worked)

    # Hours already paid for (int)
    hours_paid_for = 0

    # Beginning 'total pay' can be the decimal end, if any
    total_pay = end_pay

    while hours_paid_for < hours_worked:
        # Find the rate for the current bucket of hours
        rate_filter = (rate for (lower, upper), rate in scale.items()
                        if lower <= hours_paid_for and hours_paid_for < upper)
        current_level = next(rate_filter)

        total_pay += current_level

        hours_paid_for += 1

    return total_pay
def计算工资(薪级表、工时):
#处理以…开头的小数点(如果有)。。。首先找到“最大”速率
decimal_rate=下一个(下一个、上一个的比率),以比例表示的比率。items()
如果较低=工作小时数)
#然后计算最后一条工资
小数点=工作小时数-整数(工作小时数)
结束支付=十进制结束*十进制费率
#为便于计算,请使用整数
工时=整数(工时)
#已支付的小时数(整数)
支付的小时数=0
#起始“总工资”可以是小数点后的数字(如果有)
支付总额=最终支付
当您为<工作小时数>支付小时数时:
#查找当前时段小时数的费率
rate_filter=(比率为(下限、上限),以比例表示的比率。项()

如果低于,这里有另一种方法,使用您首先使用的费率存储方案。这种方法假设项目的工作小时数至少与
s
中的费率数相同(即
len

# Original rate scaling method
s = [80, 80, 80, 70, 70, 70, 50]

hours_worked = 15.2

final_hours_rate = s[-1]

# Handle the "decimal end"
end_pay = (hours_worked - int(hours_worked)) * final_hours_rate

hours_worked = int(hours_worked)

n_rates = len(s)

remainder = sum(s[hour] for hour in range(n_rates)) + \
            final_hours_rate * (hours_worked - n_rates)

total_pay = end_pay + remainder

总工资
是910。

看起来像是……的延伸,谢谢@JonClements。它看起来很相似,但似乎做的事情并不完全相同。今天我有点累了,想在这里自由更正一下!我添加了一个纸上计算来显示我所追求的逻辑。我建议是否有许多不同的步骤,有不同的规则-不要尝试创建一个通用的“适合所有人”的解决方案。虽然它可能使用更少的代码,并且感觉“更灵活”,一旦你忘记了为什么会有某些规则,它可能会成为维护的噩梦。相反,每个支付方案只需一个单独的函数将是最简单的。之后,只需在循环中逐小时运行,然后计算最后的分数(即天真的方法)这可能是最好的,因为你们可以花更多的时间实际制作产品,而不是计算计费公式。是的……我用它来做“免费津贴”(想象手机号码套餐),然后余额的其余部分以N的速率…所以这是一样的…但是减少每个阶段的边界…我会仔细研究一下,看看我是否已经实现了我的最终代码(100分钟免费,接下来10分钟每分钟25便士,接下来15便士等等…或者其他任何规则)-有一种感觉,我可能会为了一个更简单的方法/一些我可以访问的现有事物而放弃它to@Oli我认为你的例子是错误的,总数是910而不是940。我喜欢这个想法,但如果我正确地遵循这一点,这只适用于工作时间比刻度长的情况。小数部分按下一个费率收费,而不总是最后一个费率。例如,这里的1.2小时将返回90,应该是96。
def calculate_pay(scale, hours_worked):

    # Handle the decimal (if any) to begin with... First find the "max" rate
    decimal_rate = next(rate for (lower, upper), rate in scale.items()
                            if lower <= hours_worked and upper >= hours_worked)

    # Then calculate the last "sliver" of pay
    decimal_end = hours_worked - int(hours_worked)
    end_pay = decimal_end * decimal_rate

    # Use an integer for ease of calculation
    hours_worked = int(hours_worked)

    # Hours already paid for (int)
    hours_paid_for = 0

    # Beginning 'total pay' can be the decimal end, if any
    total_pay = end_pay

    while hours_paid_for < hours_worked:
        # Find the rate for the current bucket of hours
        rate_filter = (rate for (lower, upper), rate in scale.items()
                        if lower <= hours_paid_for and hours_paid_for < upper)
        current_level = next(rate_filter)

        total_pay += current_level

        hours_paid_for += 1

    return total_pay
# Original rate scaling method
s = [80, 80, 80, 70, 70, 70, 50]

hours_worked = 15.2

final_hours_rate = s[-1]

# Handle the "decimal end"
end_pay = (hours_worked - int(hours_worked)) * final_hours_rate

hours_worked = int(hours_worked)

n_rates = len(s)

remainder = sum(s[hour] for hour in range(n_rates)) + \
            final_hours_rate * (hours_worked - n_rates)

total_pay = end_pay + remainder