Python开关函数变体:键lambda函数

时间:2014-10-01 19:22:26

标签: python dictionary lambda switch-statement

我正在研究一个简单的映射问题,其中我有一个值,其值在给定范围内,并且该范围决定了相关的标签。这是一种典型的if / else问题,但我想知道是否可以使用字典来进行映射,将lambda放在关键方面。

mapping = {
 lambda x: x >=1 and x <= 3590:'management',
 lambda x: x >= 3600 and x <= 4690:  'service',
 lambda x: x >= 4700 and x <= 5990:  'sales',
 lambda x: x >= 6000 and x <= 7690:  'natl recs/constr/maint',
 lambda x: x >= 7700 and x <= 9790:  'product/transp',
 lambda x: x >= 9800 and x <= 9830:  'milit'
}

但是mapping[2]例如返回一个键错误,所以看起来这不是犹太教。 if / else语句系列是最好的方法吗?

更新

以下版本比上述版本更简洁,更简洁。

def mapping(x):
    if x >=1 and x <= 3590: y= 'management'
    if x >= 3600 and x <= 4690: y= 'service'
    if x >= 4700 and x <= 5990: y= 'sales'
    if x >= 6000 and x <= 7690: y= 'natl recs/constr/maint'
    if x >= 7700 and x <= 9790: y= 'product/transp'
    if x >= 9800 and x <= 9830: y= 'milit'
    return y
mapping(5556)

4 个答案:

答案 0 :(得分:3)

这个恕我直言的最佳方式是:

def mapping(x):
    if 1 <= x <= 3590: return 'management'
    if 3600 <= x <= 4690: return  'service'
    if 4700 <= x <= 5990: return  'sales'
    if 6000 <= x <= 7690: return  'natl recs/constr/maint'
    if 7700 <= x <= 9790: return  'product/transp'
    if 9800 <= x <= 9830: return  'milit'

您建议的方法会进行冗余检查。如果您正在使用if并将结果存储在y而不是立即返回,则即使您在第一个条件上成功(例如,以3000为单位),也会检查所有条件。这不是这种情况,但可以使用yelif编写。

此外,您的代码将为3595抛出异常(而此代码将返回None

答案 1 :(得分:2)

我会使用elif s,如果前面的语句评估为if,则不需要检查每个True语句,这是使用所有if发生的情况s除非你在每个if语句中return

def mapping(x):
    if 1 <= x <= 3590:
       return 'management'
    if 3600 <= x <= 4690:
       return 'service'
    if 4700 <= x <= 5990:
       return 'sales'
    if 6000 <= x <= 7690:
       return 'natl recs/constr/maint'
    if 7700 <= x <= 9790:
       return 'product/transp'
    if 9800 <= x <= 9830:
       return 'milit'

在您的代码中,您将使用elif's并将y设置为值以处理不在任何范围内的输入

def mapping(x):
    y = None
    if x >=1 and x <= 3590: y= 'management'
    elif x >= 3600 and x <= 4690: y= 'service'
    elif x >= 4700 and x <= 5990: y= 'sales'
    elif x >= 6000 and x <= 7690: y= 'natl recs/constr/maint'
    elif x >= 7700 and x <= 9790: y= 'product/transp'
    elif x >= 9800 and x <= 9830: y= 'milit'
    return y

答案 2 :(得分:2)

您可以做一些事情来使映射工作,但所有这些都很糟糕。最糟糕的方式(我想)会做类似的事情:

如果您真的想要使用看起来像项目访问权限的东西,可以试试这个:

class MapToRange(dict):

    def __getitem__(self, item):
        try:
            super(MapToRange, self).__getitem__(item)
        except KeyError:
            for key in self:
                if item in key:
                    return self[key]
            else:
                raise

mapping = MapToRange({range(   1, 3591): 'management',
                      range(3600, 4691): 'service',
                      range(4700, 5991): 'sales',
                      range(6000, 7691): 'natl recs/constr/maint',
                      range(7700, 9791): 'product/transp',
                      range(9800, 9831): 'milit'})

>>> mapping[3500]
management
>>> mapping[0]
Traceback (most recent call last):
  File "<pyshell#53>", line 1, in <module>
    mapping[0]
  File "<pyshell#46>", line 4, in __getitem__
    return super(MapToRange, self).__getitem__(item)
KeyError: 0

请注意,在Python2中,由于range创建列表而不是迭代器,因此会占用大量内存。请在Python2中尝试使用xrange

稍微快一点的安排是为每个键指定验证函数,并返回附加到返回True的第一个值的值。请注意,结果可能是意外的,因为dict是无序的,因此请考虑为此进行子类化OrderedDict

class MapToFunc(collections.OrderedDict):
    def __getitem__(self, item):
        try:
            super(MapToFunc, self).__getitem__(item)
        except KeyError:
            for key,value in self.items():
                if key(item):
                    return value
            else:
                raise

>>> mapping = MapToFunc([(lambda x:    1 <= x <= 3590, 'management'),
                         (lambda x: 3600 <= x <= 4690, 'service'),
                         (lambda x: 4700 <= x <= 5990, 'sales'),
                         (lambda x: 6000 <= x <= 7690, 'natl recs/const/maint'),
                         (lambda x: 7700 <= x <= 9790, 'product/transp'),
                         (lambda x: 9800 <= x <= 9830, 'milit')])
>>> mapping[3500]
management
>>> mapping[0]
Traceback (most recent call last):
  File "<pyshell#94>", line 1, in <module>
    mapping[0]
  File "<pyshell#90>", line 4, in __getitem__
    super(MapToFunc, self).__getitem__(item)
KeyError: 0

答案 3 :(得分:1)

在排序的边界列表上使用bisect_right可能有效:

from bisect import bisect_right

keys = [1, 3600, 4700, 6000, 7700, 9800]
values = ['management', 'service', 'sales', 'natl recs/constr/maint',
          'product/transp', 'milit']

print(values[bisect_right(keys, 5556)]) # natl recs/constr/maint