【问题标题】:More efficient code (Seemingly too many if statements)更高效的代码(看似太多的 if 语句)
【发布时间】:2017-01-30 16:34:42
【问题描述】:

我对此进行了调查,但找不到任何对我有帮助的东西(如果有类似问题的答案可能对我有帮助,我深表歉意)。我正在编写一个货币转换器,它受到大量if 的影响,看起来效率不高,我也无法想象它的可读性非常好,所以我想知道在这种情况下如何编写更高效的代码:

prompt = input("Input") #For currency, inputs should be written like "C(NUMBER)(CURRENCY TO CONVERT FROM)(CURRENCY TO CONVERT TO)" example "C1CPSP"

if prompt[0] == "C": #Looks at first letter and sees if it's "C". C = Currency Conversion
    #CP = Copper Piece, SP = Silver Piece, EP = Electrum Piece, GP = Gold Piece, PP = Platinum Piece
    ccint = int(''.join(list(filter(str.isdigit, prompt)))) # Converts Prompt to integer(Return string joined by str.(Filters out parameter(Gets digits (?), from prompt))))
    ccalpha = str(''.join(list(filter(str.isalpha, prompt)))) #Does the same thing as above expect with letters

    if ccalpha[1] == "C": #C as in start of CP
        acp = [ccint, ccint/10, ccint/50, ccint/100, ccint/1000] #Array of conversions. CP, SP, EP, GP, PP
        if ccalpha[3] == "C": #C as in start of CP
            print(acp[0]) #Prints out corresponding array conversion
        if ccalpha[3] == "S": #S as in start of SP, ETC. ETC.
            print(acp[1])
        if ccalpha[3] == "E":
            print(acp[2])
        if ccalpha[3] == "G":
            print(acp[3])
        if ccalpha[3] == "P":
            print(acp[4])
    if ccalpha[1] == "S":
        asp = [ccint*10, ccint, ccint/10, ccint/10, ccint/100]
        if ccalpha[3] == "C":
            print(asp[0])
        if ccalpha[3] == "S":
            print(asp[1])
        if ccalpha[3] == "E":
            print(asp[2])
        if ccalpha[3] == "G":
            print(asp[3])
        if ccalpha[3] == "P":
            print(asp[4])
    if ccalpha[1] == "E":
        aep = [ccint*50, ccint*5 ,ccint , ccint/2, ccint/20]
        if ccalpha[3] == "C":
            print(aep[0])
        if ccalpha[3] == "S":
            print(aep[1])
        if ccalpha[3] == "E":
            print(aep[2])
        if ccalpha[3] == "G":
            print(aep[3])
        if ccalpha[3] == "P":
            print(aep[4])
    if ccalpha[1] == "G":
        agp = [ccint*100, ccint*10, ccint*2, ccint, ccint/10]
        if ccalpha[3] == "C":
            print(agp[0])
        if ccalpha[3] == "S":
            print(agp[1])
        if ccalpha[3] == "E":
            print(agp[2])
        if ccalpha[3] == "G":
            print(agp[3])
        if ccalpha[3] == "P":
            print(agp[4])
    if ccalpha[1] == "P":
        app = [ccint*1000, ccint*100, ccint*20, ccint*10, ccint]
        if ccalpha[3] == "C":
            print(app[0])
        if ccalpha[3] == "S":
            print(app[1])
        if ccalpha[3] == "E":
            print(app[2])
        if ccalpha[3] == "G":
            print(app[3])
        if ccalpha[3] == "P":
            print(app[4])

【问题讨论】:

  • 你熟悉字典吗?
  • 我不后悔
  • 你可以使用字典来代替if语句,但是对于像你使用过的较小的表达式,效率变得毫无意义,因为if语句对于小型表达式已经快了很多。但是字典确实提供了更好的可读性。提供更好可读性的另一件事是使用 for 循环或生成器,但字典提供更好的可读性和效率,因此它是更好的选择(Efficiency comparison of if statement and dictionary)(MSeifert 提供了所需的字典)
  • 你也可以试试re模块中的正则表达式。

标签: python python-3.x if-statement optimization


【解决方案1】:

您始终可以使用字典进行查找:

lookup = {'C': {'C': ccint, 'S': ccint/10, 'E': ccint/50, 'G': ccint/100, 'P': ccint/1000},
          'S': {'C': ccint*10, 'S': ccint, 'E': ccint/10, 'G': ccint/10, 'P': ccint/100},
          'E': {'C': ccint*50, 'S': ccint*5, 'E': ccint, 'G': ccint/2, 'P': ccint/20},
          'G': {'C': ccint*100, 'S': ccint*10, 'E': ccint*2, 'G': ccint, 'P': ccint/10},
          'P': {'C': ccint*1000, 'S': ccint*100, 'E': ccint*20, 'G': ccint*10, 'P': ccint}
         }

那么你所有的ifs 大部分都被:

print(lookup[ccalpha[1]][ccalpha[3]])

但是有可能包含其他字符吗?然后你需要引入一个后备:

try:
    print(lookup[ccalpha[1]][ccalpha[3]])
except KeyError:
    # Failed to find an entry for the characters:
    print(ccalpha[1], ccalpha[3], "combination wasn't found")

如上所述,这不是最有效的方法,因为它每次都会计算每次转化(甚至是不必要的转化)。拥有基线(例如P)并保存因素可能会更有效:

lookup = {'C': 1000,
          'S': 100,
          'E': 50,
          'G': 10,
          'P': 1,
          }

# I hope I have them the right way around... :-)
print(ccint * lookup[ccalpha[3]] / lookup[ccalpha[1]])  

【讨论】:

  • 我没用过字典,好像是数组?而对于print(lookup[ccalpha[1]][ccalpha[3]]),它会去对应的字母,然后进入{}的集合中找到[3]的字母吗?我想确保我的理解是正确的。谢谢。
  • 字典由键值对组成,而不是通过索引访问项目(如数组),而是通过键访问它们,例如,如果 ccalpha[1] = 'S'ccalpha[3] = 'E' 这将首先获得'S':{'C': ccint*10, 'S': ccint, 'E': ccint/10, 'G': ccint/10, 'P': ccint/100} 的字典,然后选择 'E':ccint/10 的值。
  • 此代码计算所有可能的转换,但只使用其中一个。因此效率低下。
  • @RolandIllig 点了,我提供了一个替代方案,它不会每次都计算它们。
【解决方案2】:

与其直接从源单元转换为目标单元,不如分两步完成:

factors = { 'CP': 1, 'SP': 10, and so on }

def convert_currency(amount, from_unit, to_unit):
    copper = amount * factors[from_unit]
    return copper / factors[to_unit]

此代码就是您所需要的。你可以这样称呼它:

print(convert_currency(12345, 'SP', 'EP'))

【讨论】:

    【解决方案3】:

    另一种方法,使用矩阵(实际上只是列表的列表):

    conversion_rate = [[1, 1 / 10, 1 / 50, 1 / 100, 1 / 1000],
                       [1 * 10, 1, 1 / 10, 1 / 10, 1 / 100],
                       [1 * 50, 1 * 5, 1, 1 / 2, 1 / 20],
                       [1 * 100, 1 * 10, 1 * 2, 1, 1 / 10],
                       [1 * 1000, 1 * 100, 1 * 20, 1 * 10, 1]]
    currency_value =  {'C':0,'S': 1, 'E': 2, 'G': 3, 'P': 4}
    
    from_ = currency_value[ccalpha[1]]
    to = currency_value[ccalpha[3]]
    
    print(ccint*conversion_rate[from_][to])
    

    首先创建货币转换矩阵。 然后你将货币与一个数字匹配(很像其他语言如 C 或 Java 中的 enum)。为此,您使用字典:它就像一个列表,除了您定义索引(它不是从 0 到长度 - 1)。 然后你得到适当的转化率,乘以你的数字并打印出来。

    这与 MSeifert 答案非常相似,只是您使用的字典较少,因此如果您对这些不满意,可能会更容易理解。

    【讨论】:

    • 除了偏好之外,还有什么特别的理由可以使用其中一个(矩阵和字典)吗?
    • 这取决于你在做什么,这里我没有看到。
    猜你喜欢
    • 2014-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多