我有一个函数,它接受表达式,并将变量替换为作为输入的所有值的排列。这是我的代码,我已经测试和工作,然而,在仔细研究之后,人们说嵌套for循环是一个不好的想法,但我不确定如何使这更有效。有人能帮忙吗?谢谢。
def replaceVar(expression):
eval_list = list()
a = [1, 8, 12, 13]
b = [1, 2, 3, 4]
c = [5, 9, 2, 7]
for i in expression:
first_eval = [i.replace("a", str(j)) for j in a]
tmp = list()
for k in first_eval:
snd_eval = [k.replace("b", str(l)) for l in b]
tmp2 = list()
for m in snd_eval:
trd_eval = [m.replace("c", str(n)) for n in c]
tmp2.append(trd_eval)
tmp.append(tmp2)
eval_list.append(tmp)
print(eval_list)
return eval_list
print(replaceVar(['b-16+(c-(a+11))', 'a-(c-5)+a-b-10']))发布于 2017-04-02 21:36:33
前言
嵌套循环本身并不是坏事。只有当问题被使用时,它们才是坏的,而对于这些问题,已经找到了更好的算法(在输入大小的效率方面有好的和坏的)。例如,对整数列表进行排序就是这样一个问题。
分析问题
大小
在上面的例子中,您有三个列表,所有的大小都是4。这使得4*4*4= 64种可能的组合,如果a总是在b前面,b总是在c之前,那么至少需要64次迭代!
你的方法
在您的方法中,a的每个可能值有4个迭代,b的每个可能值有4个迭代,c的迭代相同,所以我们总共有4*4*4= 64次迭代。所以,事实上你的解决方案是相当好的!因为没有更快的方式听所有的组合,你的方式也是最好的。
风格
关于样式,可以说您可以通过更好的变量名和组合一些for循环来改进代码。例如:
def replaceVar(expressions):
"""
Takes a list of expressions and returns a list of expressions with
evaluated variables.
"""
evaluatedExpressions = list()
valuesOfA = [1, 8, 12, 13]
valuesOfB = [1, 2, 3, 4]
valuesOfC = [5, 9, 2, 7]
for expression in expressions:
for valueOfA in valuesOfA:
for valueOfB in valuesOfB:
for valueOfC in valuesOfC:
newExpression = expression.\
replace('a', str(valueOfA)).\
replace('b', str(valueOfB)).\
replace('c', str(valueOfC))
evaluatedExpressions.append(newExpression)
print(evaluatedExpressions)
return evaluatedExpressions
print(replaceVar(['b-16+(c-(a+11))', 'a-(c-5)+a-b-10']))但是,请注意,迭代的数量保持不变!
Itertools
正如凯文注意到的,您也可以使用itertools生成笛卡儿积。在内部,它将与您对组合for循环所做的操作相同:
import itertools
def replaceVar(expressions):
"""
Takes a list of expressions and returns a list of expressions with
evaluated variables.
"""
evaluatedExpressions = list()
valuesOfA = [1, 8, 12, 13]
valuesOfB = [1, 2, 3, 4]
valuesOfC = [5, 9, 2, 7]
for expression in expressions:
for values in itertools.product(valuesOfA, valuesOfB, valuesOfC):
valueOfA = values[0]
valueOfB = values[1]
valueOfC = values[2]
newExpression = expression.\
replace('a', str(valueOfA)).\
replace('b', str(valueOfB)).\
replace('c', str(valueOfC))
evaluatedExpressions.append(newExpression)
print(evaluatedExpressions)
return evaluatedExpressions
print(replaceVar(['b-16+(c-(a+11))', 'a-(c-5)+a-b-10']))发布于 2017-04-02 21:55:21
以下是一些想法:
有了这些,我才来到这里
import itertools
def replaceVar(expression):
a = ['1', '8', '12', '13' ]
b = ['1', '2', '3', '4' ]
c = ['5', '9', '2', '7' ]
expression = [exp.replace('a','{0}').replace('b','{1}').replace('c','{2}')
for exp in expression] #prepare the expresion so they can be used with format
return [ exp.format(*arg) for exp in expression for arg in itertools.product(a,b,c) ]速度增益微乎其微,但在我的机器中,它从148毫秒到125毫秒不等。
功能与R.Q.的版本相同。
发布于 2017-04-03 00:45:45
嵌套循环的“问题”基本上就是级别的数量是硬编码的。您编写了3个变量的嵌套。如果你只有两个呢?如果它跳到5点呢?那么你需要对代码做一些不平凡的手术。这就是推荐itertools.product()的原因。
与此相关的是,到目前为止,所有建议都硬编码了replace()调用的数量.同样的“问题”:如果您没有确切的3个变量,则必须修改替换代码。
与其这样做,不如考虑一种更干净的替代方法。例如,假设您的输入字符串是:
s = '{b}-16+({c}-({a}+11))'而不是:
'b-16+(c-(a+11))'也就是说,要替换的变量用大括号括起来。然后Python可以“一次”为您做所有的替换:
>>> s.format(a=333, b=444, c=555)
'444-16+(555-(333+11))'这也是对名字和名字编号的硬编码,但是同样的事情也可以用一个小块来完成:
>>> d = dict(zip(["a", "b", "c"], (333, 444, 555)))
>>> s.format(**d)
'444-16+(555-(333+11))'现在,在format()调用中,没有任何关于变量数量或它们的名称的硬编码。
元组值((333, 444, 555))正是itertools.product()返回的类型。变量名称(["a", "b", "c"])列表只能在顶部创建一次,甚至可以传递给函数。
您只需要一点代码就可以转换输入表达式,将变量名用大括号括起来。
https://stackoverflow.com/questions/43173168
复制相似问题