如何循环函数与参数的排列?



我有一个函数f(x,y),其中f(x,y) != f(y,x)

对于任何n,我想概括如下:

n = 1:C = A
n = 2:C = f(A,B) + f(B,A)
n = 3:C = f(A,f(B,B)) + f(B,f(A,B)) + f(B,f(B,A))
n = 4:C = f(A,f(B,f(B,B)) + f(B,f(A,f(B,B)) + f(B,f(B,f(A,B)) + f(B,f(B,f(B,A))

模式为:

  • n条款
  • 每个term有n-1调用f()
  • 每个术语由所有B组成,除了每个位置有一个A

这些是一个简单的方法来执行这个,所以我可以写一个函数,计算C为任何n(也给出了AB)?即C = general(A, B, n)

重复组合一个二元函数的结果通常被称为"折叠";或"reducing",它在Python中使用functools.reduce实现(或在Python 2中仅使用reduce)。有两种可能的折叠方向:左折叠,给定f[a, b, c, d, e]将返回f(f(f(f(a, b), c), d), e),右折叠,将产生f(a, f(b, f(c, f(d, e))))。默认情况下,functools.reduce实现左折叠,但可以通过交换约简函数的参数并反转要约简的列表来将其转换为右折叠。

要解决你的问题,我们不需要把列表倒过来。我们只需要以正确的顺序生成它。实际上,我们并不需要列表,因为reduce与迭代器一起工作就可以了。例如,这个简单迭代器:

def oneAatK(A, B, k, n):
"""Returns a generator which produces n values, all of them
B except for the one at index -(k+1)
"""
return (A if i + k == n - 1 else B for i in range(n))
# Using this function for f makes the results more visible.
>>> f = lambda a,b: str(a)+str(b)
>>> [* oneAatK('a', 'b', 0, 6) ]
['b', 'b', 'b', 'b', 'b', 'a']
>>> [* oneAatK('a', 'b', 2, 6) ]
['b', 'b', 'b', 'a', 'b', 'b']
def rfoldrev(f, riter):
"""Right folds f on the reverse of the sequence produced by riter"""
return reduce(lambda acc,val:f(val, acc), riter) 
>>> rfoldrev(f, oneAatK('a', 'b', 0, 6))
'abbbbb'
>>> rfoldrev(f, oneAatK('a', 'b', 2, 6))
'bbabbb'

有了它,我们可以生成你想要求和的单个项:

# This import is only needed if using Python 3
from functools import reduce
def gen(f, A, B, n):
return (rfoldrev(f, oneAatK(A, B, k, n))
for k in range(n))
>>> [* gen(f, 'a', 'b', 6) ]
['abbbbb', 'babbbb', 'bbabbb', 'bbbabb', 'bbbbab', 'bbbbba']

因为这些都是字符串,你不能把它们和sum加起来,如果f返回一个数字,你可以这样做。但是您可以使用reduce将它们与不同的二进制函数组合:

>>> reduce(lambda acc,v:f"{acc}+{v}", gen(f, 'a', 'b', 6))
'abbbbb+babbbb+bbabbb+bbbabb+bbbbab+bbbbba'

如果您正在寻找要生成的字符串,该字符串按照您的输出显示,这里有一种更简单的方法。

这是解决方案的解释。

第一行:y = [B* i + A + B* (n-(i+1)) for i in range(n)]为n个位置创建'B'字符串,同时用A

替换position第二行:if len(y) == 1: return y[0]如果输出仅为单个值,则只返回该值

第3行:else: return ' + '.join('f('+'f('.join(list(i)[:-2] + [i[-2:]]) + ')'*(len(i)-1) for i in y)如果输出是一组带有a的b,那么将它们连接为f(,每次从列表中去掉一个字符,只留下最后两个字符。这些将被合并为一个单独的集合。所有这些将被)关闭n-1次。

完整代码如下所示:

def general(A, B, n):
y = [B* i + A + B* (n-(i+1)) for i in range(n)]
if len(y) == 1: 
return y[0]
else:
return ' + '.join('f('+'f('.join(list(i)[:-2] + [i[-2:]]) + ')'*(len(i)-1) for i in y)
print ('Usecase one')
print (general ('A','B',1))
print ('Usecase two')
print (general ('A','B',2))
print ('Usecase three')
print (general ('A','B',3))
print ('Usecase four')
print (general ('A','B',4))
print ('Usecase five')
print (general ('A','B',5))

它的输出将是:

Usecase one
A
Usecase two
f(AB) + f(BA)
Usecase three
f(Af(BB)) + f(Bf(AB)) + f(Bf(BA))
Usecase four
f(Af(Bf(BB))) + f(Bf(Af(BB))) + f(Bf(Bf(AB))) + f(Bf(Bf(BA)))
Usecase five
f(Af(Bf(Bf(BB)))) + f(Bf(Af(Bf(BB)))) + f(Bf(Bf(Af(BB)))) + f(Bf(Bf(Bf(AB)))) + f(Bf(Bf(Bf(BA))))

最新更新