Iterate through sum combinations in Python 3

后端 未结 3 1395
野趣味
野趣味 2021-01-28 03:44

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()

3条回答
  •  离开以前
    2021-01-28 04:40

    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()
    

提交回复
热议问题