首页 > 解决方案 > 骑自行车者到功能列表,并结合他们的结果,直到找到匹配

问题描述

我有多个使用 lambda 调用的函数列表:

a = [ lambda: func_a1(a11, a12, a13), lambda: func_a2(a21, a23) ...]

b = [ lambda: func_b1(b11, b12), lambda: func_b2(b21) ...]

函数可以返回结果或触发异常:

def func_a1(a11, a12, a13):
  ...do something
   return result 
  raise CustomException

稍后在代码中,我将通过该函数循环。如果函数触发错误,我会跳过并继续下一个函数,否则我会返回。如果没有返回,则引发异常

def cycle1():
for f in a :
  try:
    return f()
  except CustomException:
   continue
raise CustomException

列表等类似def cycle2b

然后将来自cycle1和的结果cycle2结合起来并与事实来源进行比较。为简化起见,类似:

  a,b = cycle1(), cycle2()
  if a + b == c:
    do something

该解决方案有缺陷,因为如果不匹配不会返回尝试其他组合。如果ab等于c我想获得下一个值,但我已经无法正常工作了。例如:

有函数返回的组合(没有触发错误)。我也想先a 循环b(a循环,b状态在第一个元素上,循环将b移动到第二个元素)。

甚至可以扩展以拥有更多列表,例如a, b,c作为列表。我在想也许可以使用发电机来循环。

我需要一个想法、python 或伪代码来实现它,以避免我最初解决方案的问题

标签: python

解决方案


如果我理解正确,您想尝试所有功能组合,如果是这样,可以使用itertools.product来完成,例如

>>> import itertools
>>> list(itertools.product([1,2,3],"a b c".split()))
[(1, 'a'), (1, 'b'), (1, 'c'), (2, 'a'), (2, 'b'), (2, 'c'), (3, 'a'), (3, 'b'), (3, 'c')]
>>> 

对于您的特定用途,您可以执行以下操作,但对您的循环功能进行一些更改,稍后我将展示

for a, b in itertools.product(cycle1(), cycle2()):
    if a+b==c:
        #do something

像这样工作所需的更改是将其转换为生成器,只需将 return 更改为 yield

def cycle1():
    for f in a :
        try:
            yield f()
        except CustomException:
            continue
    #raise CustomException

作为一个生成器,它将循环遍历列表中的所有函数a,而不仅仅是在第一次成功时停止,例如return; 尽管可能会忽略最后一个例外,如果您到达产品组合的末尾,您将知道您没有找到您要搜索的内容

这是样本生成器

>>> def gen(nums):
        for n in nums:
            yield 10+n

    
>>> list(gen([1,2,3]))
[11, 12, 13]
>>> 

可以进行的另一个更改是,如果 cycle2 除了列表之外与 cycle1 相同,那么不要重复自己并让 cycle 将该列表作为参数,现在我们也有例外

def cycle(fun_list,exc=CustomException):
    for f in fun_list :
        try:
            yield f()
        except exc:
            continue

以前就是现在

for a, b in itertools.product(cycle(list_a), cycle(list_b)):
    if a+b==c:
        #do something

推荐阅读