Python beginner (junior high school student) combination generation was diagonally above (combination generation by recursive processing)

Math puzzle

Mr. K studying Python [Mathematical puzzle](https://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3% 83% 9E% E8% 84% B3% E3% 82% 92% E9% 8D% 9B% E3% 81% 88% E3% 82% 8B% E6% 95% B0% E5% AD% A6% E3% 83% 91% E3% 82% BA% E3% 83% AB-% E3% 82% B7% E3% 83% B3% E3% 83% 97% E3% 83% AB% E3% 81% A7% E9% AB% 98 % E9% 80% 9F% E3% 81% AA% E3% 82% B3% E3% 83% BC% E3% 83% 89% E3% 81% 8C% E6% 9B% B8% E3% 81% 91% E3 % 82% 8B% E3% 82% 88% E3% 81% 86% E3% 81% AB% E3% 81% AA% E3% 82% 8B70% E5% 95% 8F-% E5% A2% 97% E4% BA% 95-% E6% 95% 8F% E5% 85% 8B / dp / 479814245X / ref = asc_df_479814245X /? Tag = jpo-22 & linkCode = df0 & hvadid = 295723231663 & hvpos = 1o1 & hvnetw = g & hvrand = 6299120856193524254 & hvp & hvlocint = & hvlocphy = 100009242 & hvtargid = pla-526233948639 & psc = 1 & th = 1 & psc = 1) The second time of this.

The problem of finding a condition in which the arithmetic operation results match the reverse order of the original numbers by inserting four arithmetic operations between the four-digit numbers. Enter at least one of the four arithmetic operations. If you write the answer, 5931 5931 = 1395 This is the answer. Check by brute force and find the one that matches the conditions.

Roughly, it's a program like this.

op_table = ["","+","-","*","/"]
for number in range(1000,10000):
    for op1 in op_table:
        for op2 in op_table:
            for op3 in op_table:
                if check(number,op1, op2, op3):
                    print(number,op1, op2, op3)

Python beginner work

def Quinary(n):
    if (int(n/5)):
        return Quinary(int(n/5)) + str(n%5)
    return str(n%5)

def eval_change(a):
    b = list_change(a)
    try:
        return int(eval(b))
    except ZeroDivisionError:
        return -1
    except SyntaxError:
        return -1
   
def list_change(a):
    b = ""
    for l in a:
        b += l
    return b

table = ["","+","-","*","/"]
for i in range(1000,10000):
    for j in range(1,125):
        a = (Quinary(j).zfill(3))
        b = list(str(i))
        for k in range(3):
            b.insert(k*2+1,table[int(a[k])])
        if str(eval_change(b)) == str(i)[::-1]:
            print(i,list_change(b),"=",int(str(i)[::-1]))

Hey hey. Mr. K chose to solve it in a double loop. I feel like I chose a rather steep road, but I solved it well. Quinary seems to have searched on the net. Since there are five types of operators, the idea is to use quintuplets. I didn't have this idea.

The heart of this program is that it uses recursion to generate combinations. You can't bother to bring up a quintet, but you can generate brute force without using multiple loops, right? Besides, this method has the potential to be realized by many digits by changing the parameters.

So, let's solve this problem by a method other than the mediocre quadruple loop.

Prevent Syntax Error

Fix the part you care about before making a major remodeling

In python, if there is a 0 before the 0 number such as 01 001, a Syntax Error will occur. Therefore, eval ("1 + 001") will result in a SyntaxError. Mr. K took a strategy not to calculate in such a case. The correct answer was not this pattern, so I asked for an answer. To be precise, it is not a brute force attack, so I tried not to make an error (do not add unnecessary 0s when creating the formula). After creating the formula, there seems to be a way to delete 0 with a regular expression.

Start cooking

Combine operators Create a generator recursively to generate.

gen_sequence



a0=[["a","b"],["A","B","C"]]

def gen_sequence(a):
    for i in a[0]:
        if(len(a)>1):
            for j in gen_sequence(a[1:]):
                yield([i]+j)
        else:
            yield([i])

for x in gen_sequence(a0):
    print(x)

Execution result


['a', 'A']
['a', 'B']
['a', 'C']
['b', 'A']
['b', 'B']
['b', 'C']

Generate a combination of operators with gen_sequence and check if the condition is met by brute force. The process of generating the character string of Mr. K's formula was quite tricky, so I rewrote it to a process using zip and made it a function.

from itertools import zip_longest

op_list=[["","+","-","*","/"]]*3

def gen_sequence(a):
    for i in a[0]:
        if(len(a)>1):
            for j in gen_sequence(a[1:]):
                yield([i]+j)
        else:
            yield([i])

def build_formula(number_str, ops):
    formula = ""
    for num, op in zip_longest(number_str , ops, fillvalue=""):
        if len(formula)>1 and not formula[-2].isdigit() and formula[-1]=="0":
            #Delete the 0 immediately after the operator
            formula = formula[:-1]
        formula += num + op
    return formula

def eval_string(string):
    try:
        return eval(string)
    except ZeroDivisionError:
        return -1
           
for i in range(1000,10000):
    number_str = str(i)
    number_str_rev = number_str[::-1]
    for op in gen_sequence(op_list):
        if op ==[""]*3:
            continue
        formula = build_formula(number_str, op)
        if str(eval_string(formula)) == number_str_rev:
            print(i , formula , "=" , number_str_rev)

I tried to generate a brute force combination without using a loop. 2020/01/01 Changed to zip_longest ()

I created a gen_sequence function, but itertools.product (* op_list) was equivalent to this. Since the purpose is to create this function, I created it this time, but if you need this function, you can use itertools.product.

Recommended Posts

Python beginner (junior high school student) combination generation was diagonally above (combination generation by recursive processing)
I tried to refactor the code of Python beginner (junior high school student)
Programming beginner (junior high school student) Optimize the created algorithm
I tried to remodel the code of Python beginner (junior high school student) into object-oriented crunchy