包含别名

时间:2017-07-08 19:35:53

标签: python data-structures conditional

如何编写高效的"开关"可以为不同的输入返回相同内容的语句?
Python中的简单切换可以使用如下字典实现:

def switch(s):
    case = {'phone': '123 456 789', 'website': 'www.example.com'}
    return case[s]

这个有持续访问时间,但是我想使用别名,即switch('website')将返回与switch('site')等相同的内容而不重复值,即不使用
case = {'website': 'www.example.com, 'site': 'www.example.com}
可以使用的是:

def switch(s):
    case = {('telephone', 'number', 'phone'): '123 456 789',
            ('website', 'site'): 'www.example.com'}
    for key, value in case.items():
        if s in key:
            return value

但这种方法比线性访问时间更糟糕 它可以通过使用

使其保持不变
def switch(s):
    case = ['123 456 789', 'www.example.com']
    aliases = {'telephone': 0, 'number': 0, 'phone': 0,
               'website': 1, 'site': 1}
    return case[aliases[s]]

但是我有点重复值,如果我决定删除任何答案,我必须编辑aliases'和/或case的返回值(如果我不想再返回'123 456 789'我必须从case删除它并修改aliases以便aliases['website'] 1}}和aliases['site']返回0或在case的第一个单元格中保留虚拟值或使case成为字典

有没有更好的方法来编写这样的陈述?

3 个答案:

答案 0 :(得分:2)

您可以使用链接的哈希映射方法:

def switch(s):
    alias = {'telephone': 1, 'number': 1, 'phone': 1,
             'website': 2, 'site': 2}
    case = {1: '123 456 789', 2: 'www.example.com'}
    return case[alias[s]]

这样你就可以保持O(1)查询时间。

当然,对于真实数据,您需要自动构建aliascase地图,但这应该相当简单。

更新/删除也应该相当简单,因为它们归结为简单的dict更新/删除。

此外,为了更轻松地插入新值,您可以使用UUID4(或其他一些随机值)代替数字。

答案 1 :(得分:1)

除了原始的aliases字典之外,我只会使用没有标识别名的case字典,并使用get检查潜在的别名:

def switch(s):
    case = {'phone': '123 456 789', 'website': 'www.example.com'}
    aliases = {'telephone': 'phone', 'number': 'phone', 'site': 'website'}
    return case[aliases.get(s, s)]  # check if it's an alias or use the input as-is

这样您就不需要复制值(不在case而在alias中)。

答案 2 :(得分:0)

在你的问题中你说:

  

我想使用别名,即switch('website')会返回与switch('site')等相同的内容,而不会重复值

我认为您对重复值的关注是错误的,您不应该拒绝这种方法。添加具有相同字符串值的额外字典条目应该不是问题,这是解决问题的自然方法。如果您不需要,请不要使用额外的间接层使代码复杂化。

我假设您对该方法的关注是它可能会增加您的内存使用量,因为相同的值会在字典中存储多次。但大多数情况下,您不会有多个单独的相同字符串,而是您将对同一个字符串对象进行多次引用。由于字符串是不可变的,因此当Python看起来应该创建另一个具有相同内容的独立字符串时,Python可以替换对预先存在的对象的引用。

您可以自己测试一下。尝试创建一个包含多个相同字符串文字的字典作为值,然后测试每个字符串的id

d = {"a": "foo", "b": "foo", "c": "foo"}

for val in d.values():
    print(id(val))

在我的系统上,这告诉我id都是一样的。我认为同时编译的多个相同的字符串文字将始终转换为对单个字符串对象的多个引用。在某些情况下,由于字符串“interning”,具有特定内容的所有字符串(通常看起来可能是标识符的字符串)将在程序中的任何位置共享。但是你可能不需要过多关注细节。要认识到的重要一点是,重复的字符串在大多数情况下可能不会使用过多的内存。

我想不出任何其他理由反对将所有别名添加到单个字典中。这是天生的解决方案,所以我就是这样做的。如果以后内存使用成为一个问题,你可能会重新访问字典,仔细检查它是否填充了重复的引用,而不是重复的对象,但我怀疑它在任何严重程序的规模上都很重要。

拥有易于使用和理解的代码更为重要。

正如您所评论的那样,您的主要关注点不是重复自己,您可能希望使用代码设置字典来转换另一个稍微不那么冗余的数据结构,而不是直接将其作为文字结构。

例如,下面的代码使用字典理解来将一个将别名子列表与其值配对的列表转换为易于搜索的字典:

_data = [     # contains (alias_list, value) 2-tuples
    (['telephone', 'number', 'phone'], '123 456 789'),
    (['website', 'site'], 'www.example.com'),
]

case = {alias: value for aliases, value in _data for alias in aliases}

您可能希望将此代码放在仅运行一次的位置(例如,在顶层,或在某个类或实例变量中),而不是每次switch函数都运行字典理解叫做。因为字典是可变的,所以Python不会假设它可以为每个调用使用相同的dict对象(即使它总是具有相同的值)。