简体   繁体   中英

How to get all mathematical combinations of a list that equal a result number in Python

Background

We have a family tradition where my and my siblings' Christmas presents are identified by a code that can be solved using only numbers related to us. For example, the code could be birth month * age + graduation year (This is a simple one). If the numbers were 8 * 22 + 2020 = 2196 , the number 2196 would be written on all my Christmas presents.

I've already created a Python class that creates a list for every sibling with every number related to them. Currently the list is over 30 numbers, but it may grow to over 40.

Question

Is there any way to test all the mathematical combinations of a list of numbers that equal a result number? For example, findPossibleCombinations( [8, 7, 4, 22, 2020, 573], 2196 ) returns a list of lists that can create the result number? So this function would return [8, 22, 2020] and any other lists it found that could be used to equal 2196. No number will ever be used more than once.

I'm sure there's a way to do it that would result in an O(N^47) algorithm (Joking, of course), but am wondering what the most optimized algorithm to accomplish this kind of outcome is?

For the sake of computational time, limit the number of operations to 5-6 total. My parents aren't crazy and would probably never use more than 5-6 numbers to calculate the end result. I'd also limit operations to +, -, * and /, though I may need to add other operations for future years.

Thank you for any and all help. I hope you at least get a laugh out of my weird family tradition.

Edit: Here's my class structure. It could be optimized a lot more, but good enough for now. Any strings are converted to alphanumeric and inverse alphanumeric and added by letter. The "listofnums" is the list I'd want to use.

def getalpha( str, inverse ):
   "Converts string to alphanumeric array of chars"
   array = []
   for i in range(0, len(str)): 
      alpha = ord(str[i]) - 96
      if inverse:
        array.append(27 - alpha)
      else:
        array.append(alpha)
   return array;

class Person:
  def __init__(self, name, middlename, birthmonth, birthday, birthyear, age, orderofbirth, gradyear, state, zip):
    #final list
    self.listofnums = []
    self.listofnums.extend((birthmonth, birthday, birthyear, birthyear - 1900, age, orderofbirth, gradyear, gradyear - 2000, zip))
    letters = name + middlename + state
    #add all related alphanumeric letters
    self.listofnums.extend(getalpha(letters, False))
    self.listofnums.extend(getalpha(letters, True))

You need itertools.product . It gives a generator which yield all the tuples of the cartesian product of the sequences given.

from itertools import product

values1 = range(3)     # replace with your candidate birth month values
values2 = range(3, 6)  # replace with your candidate age values
values3 = range(7, 9)  # replace with your candidate graduation year values 
target_values = {10, 20, 30}  # replace with your target values (results)
# target_values need to be a set for efficient lookup.
for val1, val2, val3 in product(values1, values2, values3):
    if val1 + val2 + val3 in target_values:  #replace with your function
        print(val1, val2, val3)

Ismael had a great response that got me on the right track. I had to combine a permutation of all operations with a combination of all numbers to get a list of all possible sets (of a list of numbers and a list of operations) that would reach a number in the target values.

This answer does assume a constant to define the number of operations in the solution

#Master algorithm (Get the result set of all combinations of numbers and cartesian products of operations that reach a target_value, using only the number_of_numbers_in_solution)
#Example: sibling1.results[1] = [(3, 22, 4), (<built-in function add>, <built-in function add>), 29]. This means that 3 + 22 + 4 = 29, and 29 is in target_values

NUMBER_OF_OPERATIONS_IN_SOLUTION = 3
NUMBER_OF_NUMBERS_IN_SOLUTION = NUMBER_OF_OPERATIONS_IN_SOLUTION + 1
TARGET_VALUES = {22,27,29,38,39}

import operator
from itertools import product
from itertools import combinations

def getresults( list ):
  #Add the cartesian product of all possible operations to a variable ops
  ops = []
  opslist = [operator.add, operator.sub, operator.mul, operator.truediv]
  for val in product(opslist, repeat=NUMBER_OF_OPERATIONS_IN_SOLUTION):
    ops.append(val)

  #Get the result set of all combinations of numbers and cartesian products of operations that reach a target_value
  results = []
  for x in combinations(list, NUMBER_OF_NUMBERS_IN_SOLUTION):
      for y in ops:
          result = 0
          for z in range(len(y)):
              #On the first iteration, do the operation on the first two numbers (x[z] and x[z+1])
              if (z == 0):
                  result = y[z](x[z], x[z+1])
              #For all other iterations, do the operation on the current result and x[z+1])
              else:
                  result = y[z](result, x[z+1])
      if result in TARGET_VALUES:
          results.append([x, y, result])
  print(len(results))
  return results

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM