Python - 在类似表的方案中查找值的最佳方法

时间:2016-08-15 10:56:04

标签: python

我有一位客户想要一种计算运费的方法。它是按重量和公里计算的(不幸的是不是线性的)。它看起来像这样:

|           | To 50km   | To 100km  | To 150km  | To 200km  |
|-------    |---------  |---------- |---------- |---------- |
| 10kg      | 84€       | 95€       | 104.45€   | 116€      |
| 20kg      | 98€       | 108.50€   | 117.10€   | 127.20€   |
| 30kg      | 112.40€   | 121.20€   | 129.95€   | 149.30€   |

我想通过调用类似calc_shipping_costs(range, weight)的函数来查找值,例如calc_shipping_costs(100, 20),然后接收 108.50€

这样做的最佳方法是什么?

2 个答案:

答案 0 :(得分:0)

所以如果有人想知道的话。我是这样做的:

def calc_shipping_cost(weight, kilometer):

    WEIGHT_BREAKPOINTS = [10, 20, 40, 60, 80, 100, 500]
    KILOMETER_BREAKPOINTS = [50, 100, 150, 200, 999]

    prices = [
        [84.85, 95.15, 104.45, 116.70, 122.25],
        [98.65, 108.45, 117.20, 127.95, 134.60],
        [112.40, 121.70, 129.95, 149.30, 153.10],
        [139.95, 148.20, 155.45, 173.10, 177.80],
        [153.70, 167.50, 168.20, 193.20, 196.30],
        [181.25, 188.00, 193.70, 225.85, 227.15],
        [208.80, 214.50, 219.20, 281.00, 282.70],
    ]

    row = WEIGHT_BREAKPOINTS.index(weight)
    col = KILOMETER_BREAKPOINTS.index(kilometer)

    return prices[row][col]

答案 1 :(得分:0)

我同意这个问题可以被视为偏离主题,但是,这一次,这是一个现实世界的问题需要解决,而不是学生的问题。

不幸的是,您提供的解决方案是错误的:您只考虑可以拥有“断点”值。如果您给出不同的权重(例如21)或公里(例如55),则该函数会引发异常:

>>> calc_shipping_cost(20, 50)
98.65

>>> calc_shipping_cost(21, 55)
Traceback (most recent call last):
  File "python", line 1, in <module>
  File "python", line 16, in calc_shipping_cost
ValueError: 21 is not in list

表格显示“To 50km”,“To 100km”等。所以你需要一个更宽容的功能并考虑间隔:例如:[0,50 [,[50,100 [等等]

要在有序的间隔列表中选择值的索引,可以考虑数组二分算法。 Python在bisect模块中有效地实现了该算法。它通常用于计算有序数组中项的插入点。

例如:

>>> import bisect

>>> WEIGHT_BREAKPOINTS = [10, 20, 40, 60, 80, 100, 500]
>>> bisect.bisect_left(WEIGHT_BREAKPOINTS, 10)
0
>>> bisect.bisect_left(WEIGHT_BREAKPOINTS, 40)
2
>>> bisect.bisect_left(WEIGHT_BREAKPOINTS, 25)
2

对于最后一个例子,插入点25是索引2(在40之前插入,索引也是2)。

如果“超出范围”,您可以提出自己的例外或只是ValueError

这是一个更好的实现:

import bisect

def calc_shipping_cost(weight, kilometer):

    WEIGHT_BREAKPOINTS = [10, 20, 40, 60, 80, 100, 500]
    KILOMETER_BREAKPOINTS = [50, 100, 150, 200, 999]

    prices = [
        [84.85, 95.15, 104.45, 116.70, 122.25],
        [98.65, 108.45, 117.20, 127.95, 134.60],
        [112.40, 121.70, 129.95, 149.30, 153.10],
        [139.95, 148.20, 155.45, 173.10, 177.80],
        [153.70, 167.50, 168.20, 193.20, 196.30],
        [181.25, 188.00, 193.70, 225.85, 227.15],
        [208.80, 214.50, 219.20, 281.00, 282.70],
    ]

    row = bisect.bisect_left(WEIGHT_BREAKPOINTS, weight)
    col = bisect.bisect_left(KILOMETER_BREAKPOINTS, kilometer)

    try:
        return prices[row][col]
    except IndexError:
        raise ValueError(weight, kilometer)

具有以下行为:

>>> calc_shipping_cost(10, 50)
84.85
>>> calc_shipping_cost(10.0, 50)
84.85
>>> calc_shipping_cost(20, 50)
98.65
>>> calc_shipping_cost(21, 55)
121.7
>>> calc_shipping_cost(10.0, 50)
84.85
>>> calc_shipping_cost(500, 50)
208.8
>>> calc_shipping_cost(1000, 50)
Traceback (most recent call last):
  File "python", line 1, in <module>
  File "python", line 24, in calc_shipping_cost
ValueError: (1000, 50)