在Python 3中迭代求和组合



我正在寻找一种方法来找到具有相同值的给定极限的斐波那契序列元素的总和的所有组合。我知道itertools中的combinations()是解决此类问题的最佳选择,但作为Python的新手,我想知道如何保留匹配的组合(因为只有一个是正确的,因为这不是算法的结束)。

我现在有:

 # Call Fibonacci sequence with a given limit:
 def fib1(n): 
     result = []
     a, b = 1, 1
     while a < n:
         result.append(a)
         a, b = b, a + b
     return result

# Wrong code, skeleton:
def zeckendorf(n):
    from itertools import combinations
    seq = fib1(n)
    row = []
    sum = 0
    for i in combinations(seq, len(seq)):
        sum += i
        row.append(i)
        if sum > n:
            sum = 0
            row = []
            continue
        elif sum == n:
            break
    return row

现在我知道第二位在很多方面都是错误的。此外,我还犯了一个错误,试图将元组添加到整数中。我只需要知道如何使用itertools模块分别迭代这些组合的单独元素。只有带有sum 'n'的组合对我有用

如果我正确理解你想要实现的目标,那么使用以下代码:

def zeckendorf(n):
    seq = fib1(n)
    for i in range(1, len(seq)):
        for comb in itertools.combinations(seq, i):
            if sum(comb) == n:
                return list(comb)
    return []

如果你需要这段代码的进一步解释,就问:)

要查找所有具有所需和的组合,请将每个组合附加到结果列表中:

def combinations_with_sum(sequence, desired_sum):
    results = []
    for i in range(len(sequence)):
        results.extend([combination for combination in combinations(sequence, i)
                        if sum(combination) == desired_sum])
    return results

假设你想用sum <max_summin_termsmax_terms之间的元素数目>

这里有几种方法可以做到这一点,我包括整个脚本,使其更容易测试和玩耍,但基本上你只需要* LimitedSums()函数来获得答案。

暴力方法是遍历所有子集,并检查每个子集的元素和数量。这实际上就是SlowLimitedSums()所做的——尽管它利用itertools.combinations()来迭代子集,并且不考虑多于max_terms元素的子集。

可能更有效的方法是只考虑总和小于max_sum的子集。如果您正在递归地构建子集,只要当前子集的总和超过max_sum(假设所有输入数字都是非负的),或者元素的数量超过max_terms,您就可以简单地停止递归。这在FasterLimitedSums()中实现。

请注意,在最坏的情况下,您的结果将包含所有2^len(v)子集-在这种情况下,*LimitedSums()的两个版本之间应该没有明显的运行时间差异。

import itertools
import random

def SlowLimitedSums(v, max_sum, min_terms=None, max_terms=None):
  min_terms = 0 if min_terms is None else min_terms
  max_terms = len(v) if max_terms is None else max_terms
  return sorted(set(
      sum(c) for nc in range(min_terms, max_terms + 1)
      for c in itertools.combinations(v, nc)
      if sum(c) <= max_sum))

def FasterLimitedSums(v, max_sum, min_terms=None, max_terms=None):
  l = sorted(v)
  n = len(v)
  min_terms = 0 if min_terms is None else min_terms
  max_terms = n if max_terms is None else max_terms
  result = set([])
  def RecursiveSums(s, n_terms, start_pos):
    if start_pos >= n or s > max_sum or n_terms > max_terms:
      return
    if n_terms >= min_terms:
      result.add(s)
    for p in range(start_pos, n):
      RecursiveSums(s + v[p], n_terms + 1, p + 1)
  RecursiveSums(0, 0, -1)
  return sorted(result)

def main():
  mass_list = [4, 1, 8]
  mass = 10
  print(sorted(mass_list + SlowLimitedSums(mass_list, mass, min_terms=2)))
  print(sorted(mass_list + FasterLimitedSums(mass_list, mass, min_terms=2)))

if __name__ == "__main__":
  main()

最新更新