【问题标题】:Python - Best way to lookup values in a table-like schemePython - 在类表方案中查找值的最佳方法
【发布时间】:2016-08-15 10:56:04
【问题描述】:

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

|           | 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€

最好的方法是什么?

【问题讨论】:

  • 第一步是尝试自己编写函数。
  • range 参数是什么?公里?
  • @Pureferret 我不想让任何人在这里发布函数。这是关于提供有关查找这些值的最佳方法的建议。
  • 看看pandas。看来这对你来说是个不错的选择。
  • @Dominic 我担心这可能会使 Stack Overflow 偏离主题,不幸的是

标签: python


【解决方案1】:

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

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]

【讨论】:

    【解决方案2】:

    我同意这个问题可以被认为是题外话,但是,这一次,这是一个需要解决的现实问题,而不是学生问题。

    不幸的是,您给出的解决方案是错误的:您只考虑可以拥有“断点”值。如果您给出不同的 weight(例如 21)或 kilometer(例如 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[, etc.

    要在间隔的有序列表中选择一个值的索引,您可以考虑使用数组二分算法。 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(要插入到索引也是 2 的 40 之前)。

    如果出现“超出范围”,您可以提出自己的异常或简单地提出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)
    

    【讨论】:

    • 嘿劳伦特。感谢您的回答。在我的“真实”函数中,我有一个“向上取整”函数,它会将值四舍五入到下一个已知断点。
    猜你喜欢
    • 1970-01-01
    • 2017-03-11
    • 2014-12-29
    • 2010-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-05
    • 2021-06-01
    相关资源
    最近更新 更多