如何将范围映射转换为字典

How to convert a mapping of ranges into a dictionary

如何将其转换成字典?

if grade>=96.5:return 5.83
elif grade>=92.5:return 5.5
elif grade>=89.5:return 5.16
elif grade>=86.5:return 4.83
elif grade>=82.5:return 4.5
elif grade>=79.5:return 4.16
elif grade>=76.5:return 3.83
elif grade>=72.5:return 3.5
elif grade>=69.5:return 3.16
elif grade>=68.5:return 2.83
elif grade>=64.5:return 2.5
else:return 0

我知道如何制作基本词典,但是,我不确定它是否会像这样:

grade_checker = {
    grade>96.5:5.83
}

谢谢!

无法将此逻辑转换为字典。字典是键值对,因此您无法仅通过查找的方式进行 "greater than" 检查。

简短的回答是您应该将其转换为字典。这最适合用作函数,而且您似乎只是缺少函数定义,因为我看到您在代码中使用 return 。字典是由键值对构成的,并且由于您的条件涉及 >= 评估,因此字典不合适。请参阅下面的功能实现:

def grade_checker(grade):

    if grade>=96.5: return 5.83
    elif grade>=92.5: return 5.5
    elif grade>=89.5: return 5.16
    elif grade>=86.5: return 4.83
    elif grade>=82.5: return 4.5
    elif grade>=79.5: return 4.16
    elif grade>=76.5: return 3.83
    elif grade>=72.5: return 3.5
    elif grade>=69.5: return 3.16
    elif grade>=68.5: return 2.83
    elif grade>=64.5: return 2.5
    else: return 0

grade_checker(75)
grade_checker(62)
grade_checker(94)

Returns:

3.5
0
5.5

如果您确实需要使用字典,这将是一种方法;以字典键作为条件校验值,字典值作为返回值

grade_checker = {
    96.5: 5.83,
    92.5: 5.5,
    89.5: 5.16,
    86.5: 4.83,
    82.5: 4.5,
    79.5: 4.16,
    76.5: 3.83,
    72.5: 3.5,
    69.5: 3.16,
    68.5: 2.83,
    64.5: 2.5
}

def check_grade(grade):
    for k in grade_checker:
        if grade >= k:
            return grade_checker[k]
    return 0

检查:

>>> check_grade(45.5)
0
>>> check_grade(65.5)
2.5
>>> check_grade(95)
5.5

如果你在3.6之前使用Python,你可以使用collections.OrderedDict (including Python 2.7), otherwise dict objects are natively insertion-sorted ()!

有了它,您可以简单地迭代 dict 和 return 第一个范围匹配。

# python 3.6+
grade_table = {
    96.5: 5.83,
    ...
    64.5: 2.5,
}

# pre-3.6
from collections import OrderedDict
grade_table = OrderedDict((  # this is a tuple of tuples
    (96.5, 5.83),
    ...
    (64.5, 2.5),
))

def fn(student_grade):
    for grade, value in grade_table.iteritems():
        if student_grade >= grade:
            return value

    return 0  # default

请注意,如果您希望 table 发生变化,那么测试您的字典是否按降序排列或始终接受可迭代对象的可迭代对象然后对它们进行排序可能是有意义的(我使用元组的元组以上,但任何相同形式的东西都应该可以工作并且易于排序)否则它将 return 不正确的结果。

另一种选择是使用 range-key-dict:

from range_key_dict import RangeKeyDict

range_key_dict = RangeKeyDict({
    (96.5, 100): 5.83,
    (92.5, 96.5): 5.5,
    (89.5, 92.5): 5.16,
    (86.5, 89.5): 4.83,
    (82.5, 86.5): 4.5,
    (79.5, 82.5): 4.16,
    (76.5, 79.5): 3.83,
    (72.5, 76.5): 3.5,
    (69.5, 72.5): 3.16,
    (68.5, 69.5): 2.83,
    (64.5, 68.5): 2.5,
    (0, 64.5): 0
})

assert range_key_dict[96.5] == 5.83
assert range_key_dict[96.4] == 5.5
assert range_key_dict[96.49] == 5.5

您可以使用 pip install range-key-dict 安装此 Python 软件包。

您还需要检查源代码的复杂性,因为这不会像常规词典那样维护 O(1) 散列。

仅使用常规 if 语句可能更容易、更高效。

如果您想存储键值对并希望能够非常快速地检索任意条目,则字典特别有用。正如其他答案所示,您只需要遍历元素序列并使用第一个匹配的值。因此,最直接(也可能是最有效)的策略是使用序列数据类型。这是代码中的样子:

pairs = (
    (96.5, 5.83),
    (92.5, 5.5),
    (89.5, 5.16),
    (86.5, 4.83),
    (82.5, 4.5),
    (79.5, 4.16),
    (76.5, 3.83),
    (72.5, 3.5),
    (69.5, 3.16),
    (68.5, 2.83),
    (64.5, 2.5),
)

def get_grade(g):
    for grade, value in pairs:
            if g >= grade:
                return value
    return 0

听写很棒,但如果您不需要它们的功能,请使用更简单的东西。

如果您可以使用第 3 方库,则可以通过 pd.cut 使用 Pandas。如果您有大量输入成绩要分类,这将特别有效。

import pandas as pd

grade_checker = {96.5: 5.83,
                 ...,
                 64.5: 2.5}

keys, values = zip(*sorted(grade_checker.items()))
keys += (float('inf'),)  # need to add upper boundary for pd.cut input

grade = 65.5
res = pd.cut([grade], keys, labels=values).astype(float)[0]  # 2.5

查看相关内容:

没有字典,你可以这样解决问题:

import numpy as np
GRADES = np.array(
    [[96.5 , 92.5 , 89.5 , 86.5 , 82.5 , 79.5 , 76.5 , 72.5 , 69.5 , 68.5 , 64.5 ],
     [ 5.83,  5.5 ,  5.16,  4.83,  4.5 ,  4.16,  3.83,  3.5 ,  3.16, 2.83,  2.5 ]])
def get_grade(grade):
    try:
        return GRADES[1][grade > [GRADES[0]][0]
    except:
        return 0

这比字典更可取,因为内置字典只对 >= Python 3.6 保证有序性(即,它们将按照插入 keys/values 的顺序迭代)。能够 运行 编写更多 Python 版本的代码比依赖于特定版本的详细信息更可取。

可以使用字典来保存评分信息,但它并没有真正提供任何好处,因为您不能对这些范围使用快速字典查找。相反,我建议使用 (points, grade) 对的排序列表,然后使用 bisect 二进制搜索 O(logn) 中的匹配分数。

>>> import bisect
>>> grade_ranges = [(0, 0), (64.5, 2.5), (68.5, 2.83), (69.5, 3.16), 
...                 (72.5, 3.5), (76.5, 3.83), (79.5, 4.16), (82.5, 4.5), 
...                 (86.5, 4.83), (89.5, 5.16), (92.5, 5.5), (96.5, 5.83)]
...
>>> points, grade = zip(*grade_ranges)
>>> grade[bisect.bisect(points, 96.5)-1]
5.83
>>> grade[bisect.bisect(points, 73)-1]
3.5
>>> grade[bisect.bisect(points, 30)-1]
0

grade_ranges 解压缩到 pointsscores 在这里是可选的,但恕我直言,这样更简洁。如果不解压缩,则必须将元组传递给 bisect,例如bisect(grade_ranges, (55,))

我不是数学家,但我认为插值法可能对此有用?

    from numpy import interp

    ak = [k for k in gc.keys()]
    av = [v for v in gc.values()]

    # np.interp needs values from lowest to highest
    ak.reverse()
    av.reverse()

    interp(79, ak, av)
    >>> 4.105

    interp(96, ak, av)
    >>> 5.78875

    interp(64, ak, av)
    >>> 2.5

您需要向上填充到 100 并向下填充,因为它是 插值 ,因此您感兴趣的数据点需要在 采样范围。