Search code examples
pythonpython-itertools

Applying arithmetic operations on list of numbers without repetition in python


We've got the following python list: [1,2,3,10] I would like to accomplish the following: Create a function that takes in the list and figures out from the list of arithmetic operations: ['+', '-', '/','*'] which combinations give us 6 as the answer. We don't want repetition so we don't want 2*3 and 3*2 in our solution. We do want to list the numbers we haven't used so that's (1 and 10 here). Same for 2/1*3=6.0, 2*3/1=6.0, 3/1*2=6.0, 3*2/1=6.0 are all considered equivalent since we use the same numbers regardless of operations and have not used 10. I want the function to be general enough so that I can use it from there for numbers from 1 to 9. Your help is appreciated. I tried using itertools and permutation to get a list of all possible combinations but this seems unnecessary and produces the problem that 2/1*3=6.0, 2*3/1=6.0, 3/1*2=6.0, 3*2/1=6.0 are included in the list and this is difficult to filter out.

Example where I got using itertools:


from itertools import chain, permutations

def powerset(iterable):
  xs = list(iterable)
  return chain.from_iterable(permutations(xs,n) for n in range(len(xs)+1) )

lst_expr = []
for operands in map(list, powerset(['1','2','3','10'])):
    n = len(operands)
    #print operands
    if n > 1:
        all_operators = map(list, permutations(['+','-','*','/'],n-1))
        #print all_operators, operands
        for operators in all_operators:
            exp = operands[0]
            i = 1
            for operator in operators:
                exp += operator + operands[i]
                i += 1

            lst_expr += [exp]

lst_stages=[]

for equation in lst_expr:
    if eval(equation) == 6:
        lst_stages.append(equation)
        eq = str(equation) + '=' + str(eval(equation))
        print(eq)

Solution

  • Here is possible solution. We need to keep a sorted tuple of used numbers to avoid duplicates like 2*3 and 3*2.

    from itertools import chain, permutations
    
    def powerset(iterable):
      xs = list(iterable)
      return chain.from_iterable(permutations(xs,n) for n in range(len(xs)+1) )
    
    lst_expr = []
    for operands in map(list, powerset(['1','2','3','10'])):
        n = len(operands)
        #print operands
        if n > 1:
            all_operators = map(list, permutations(['+','-','*','/'],n-1))
            #print all_operators, operands
            for operators in all_operators:
                exp = operands[0]
                numbers = (operands[0],)
                i = 1
                for operator in operators:
                    exp += operator + operands[i]
                    numbers += (operands[i],)
                    i += 1
    
                lst_expr += [{'exp': exp, 'numbers': tuple(sorted(numbers))}]
    
    lst_stages=[]
    numbers_sets = set()
    
    for item in lst_expr:
        equation = item['exp']
        numbers = item['numbers']
        if numbers not in numbers_sets and eval(equation) == 6:
            lst_stages.append(equation)
            eq = str(equation) + '=' + str(eval(equation))
            print(eq, numbers)
            numbers_sets.add(numbers)
    

    Output:

    2*3=6 ('2', '3')
    1+10/2=6.0 ('1', '10', '2')
    2/1*3=6.0 ('1', '2', '3')