Iterate through sum combinations in Python 3

ぃ、小莉子 提交于 2019-12-20 07:28:22

问题


I'm look for a way to find all combinations of sums with elements of a Fibonacci sequence with a given limit which equal that same value. I know that combinations() from itertools is our best bet in solving such problems, but as I'm new in Python I like to know how I can retain the matching combinations (as only one is correct, as this is not the end of the algorithm).

I currently have:

 # 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

Now I know the second bit is wrong in many ways. Also, I make the mistake as to try to add tuples to integers. I just need to know how I can iterate through separate elements of those combinations separately using the itertools module. Only the combinations with sum 'n' are useful to me.


回答1:


If I understand correctly what you are trying to achieve then use the following code:

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 []

If you need further explanation on this code just ask :)




回答2:


To find all the combinations with the desired sum, append each combination to a result list:

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



回答3:


Let's say you want to find all subsets of your input with sum < max_sum and the number of elements between min_terms and max_terms.

Here is a couple of ways to do it, I'm including the whole script to make it easier to test and play around with but basically you only need *LimitedSums() functions to get the answer.

Brute-force approach is to iterate through all subsets and check the sum and the number of elements for each subset. That's effectively what SlowLimitedSums() does - although it takes advantage of itertools.combinations() to iterate through subsets and doesn't consider subsets with more than max_terms elements.

Potentially more efficient approach is to only consider the subsets which sum up to less than max_sum. If you are building subsets recursively you can simply stop recursion as soon as the sum of your current subset exceeds max_sum, assuming all your input numbers are non-negative, or the number of elements exceeds max_terms. This is implemented in FasterLimitedSums().

Note that in the worst case your result will contain all 2^len(v) subsets - in this case there should be no significant running time difference between the two versions of *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()


来源:https://stackoverflow.com/questions/15701692/iterate-through-sum-combinations-in-python-3

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!