如何使用参数置换在函数上循环?

2024-05-13 09:11:20 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个函数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个术语
  • 每个术语都有n-1f()的调用
  • 每个术语由所有的B组成,除了每个位置有一个A

这是执行此操作的简单方法吗?这样我就可以编写一个函数,为任何n计算C(同时给出AB)?i、 e.C = general(A, B, n)


Tags: 方法函数模式general术语
2条回答

重复组合二进制函数的结果通常被称为“折叠”或“减少”,它在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实现左折叠,但可以通过将参数交换到reduced函数并反转要缩减的列表来将其转换为右折叠

为了解决您的问题,我们不需要颠倒列表。我们只需要按照正确的顺序生成它。事实上,我们并不真正需要一个列表,因为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'

如果您希望生成一个按照输出显示的字符串,这里有一个更简单的方法

下面是解决方案的解释

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

第2行: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))))

相关问题 更多 >