簡體   English   中英

對列表中所有可能的數字組合進行算術計算

[英]Performing arithmetic calculations on all possible digit combinations in a list

我以這樣的格式創建數據:

initial_data = [
"518-2", '533-3', '534-0',
'000-3', '000-4']

我需要對連字符之前的部分執行幾個操作(add、sub、div、mult、factorial、power_to、root),看看是否有一個方程等於連字符之后的部分。

像這樣:

#5182
-5 - 1 + 8 = 2 or 5*(-1) - 1 + 8 = 2

#000-3
number, solution, number_of_solutions
000-3,(0! + 0!) + 0! = 3,2

or
000-4,,0
or 
533-3,5 - (3! / 3) = 3,5

連字符之前的部分中的每個數字都可以有相反的符號,所以我發現了這個:

def inverter(data):

    inverted_data = [-x for x in data]
    res = list(product(*zip(data, inverted_data)))
    return res

我應該像上面的示例一樣創建一個 CSV 文件,但我還沒有完成那部分,這似乎是最簡單的部分。 我所擁有的是幾個不同的部分,我無法以合理的方式連接它們:

import numpy as np
from itertools import product
from math import factorial

def plus(a, b):
    return a + b

def minus(a, b):
    return a - b

def mult(a, b):
    return a * b

def div(a, b):
    if b!=0:
        if a%b==0:
            return a//b
    return np.nan

def the_factorial(a, b):
    try:
        return factorial(int(a))
    except ValueError:
        return np.nan
        
def power_to(a:int, b:int)->int:
    try:
        return int(a**b)
    except ValueError:
        return np.nan

def root(a:int, b:int)->int:
    try:
        return int(b**(1 / a))
    except (TypeError, ZeroDivisionError, ValueError):
        return np.nan

def combinations(nums, funcs):
    """Both arguments are lists"""
    t = []
    for i in range(len(nums)-1):
        t.append(nums)
        t.append(funcs)
    t.append(nums)
    return list(itertools.product(*t))

def solve(instance):
    instance = list(instance)
    for i in range(len(instance)//2):
        b = instance.pop()
        func = instance.pop()
        a = instance.pop()
        instance.append(func(a, b))
    return instance[0]

def main():
    try:
        # a = [1, 3 ,4]
        a = [int(-5), int(-1), int(8)]
        func = [plus, minus, mult, div, the_factorial, power_to, root]
        combs = combinations(a, func)
        solutions = [solve(i) for i in combs]
        for i, j in zip(combs, solutions):
            print(i, j)
    except ValueError:
        #If there's too many combinations
        return np.nan

我在將數據從 initial_data 轉換為 inverter 到 main 時遇到問題,目前僅適用於一個示例,並返回一個丑陋的讀數,中間為 function object。

提前致謝。

我認為這會對你有很大幫助(調整在你身上)但它不會寫在 CSV 中,我留給你嘗試,只是考慮到有數千種可能的組合,在某些情況下,結果真的很大(請參閱main()中的注釋)。

為了清晰和成功的linting (與舊的 Python 版本兼容),我在 function 聲明中添加了缺失的類型。 另外,我認為不需要 function combinations()所以我刪除了它。 在我提議的代碼中,function solve()是一個神奇的代碼:)

說了這么多,這里是完整的代碼:

import numpy as np
from itertools import product
from math import factorial
from typing import Union, Callable, Tuple, List, Set


def plus(a: int, b: int) -> int:
    return a + b


def minus(a: int, b: int) -> int:
    return a - b


def mult(a: int, b: int) -> int:
    return a * b


def div(a: int, b: int) -> Union[int, float]:
    try:
        retval = int(a / b)
    except (ValueError, ZeroDivisionError):
        retval = np.nan
    return retval


def the_factorial(a: int) -> Union[int, float]:
    try:
        return factorial(int(a))
    except ValueError:
        return np.nan
    except OverflowError:
        return np.inf


def power_to(a: int, b: int) -> Union[int, float]:
    try:
        return int(a ** b)
    except (ValueError, ZeroDivisionError):
        return np.nan


def root(a: int, b: int) -> Union[int, float]:
    try:
        return int(b ** (1 / a))
    except (TypeError, ZeroDivisionError, ValueError):
        return np.nan


def solve(values: Tuple[int, int, int], ops: List[Callable]) -> list[Tuple[str, int]]:
    # Iterate over available functions.
    combs = list()
    for f in FACTORS:
        # Get values to operate with.
        x, y, z = values
        sx, sy, sz = x, y, z
        a, b, c = f
        # Calculate the factorial for the values (if applicable).
        if a == 1:
            sx = f"{x}!"
            x = the_factorial(x)
        if b == 1:
            sy = f"{y}!"
            y = the_factorial(y)
        if c == 1:
            sz = f"{z}!"
            z = the_factorial(z)
        for ext_op in ops:  # External operation.
            for int_op in ops:  # Internal operation.
                # Create equations by grouping the first 2 elements, e.g.: ((x + y) * z).
                eq_str = f"{ext_op.__name__}({int_op.__name__}({sx}, {sy}), {sz})"
                eq_val = ext_op(int_op(x, y), z)
                combs.append((eq_str, eq_val))
                # Create equations by grouping the last 2 elements, e.g.: (x + (y * z)).
                eq_str = f"{ext_op.__name__}({sx}, {int_op.__name__}({sy}, {sz}))"
                eq_val = ext_op(x, int_op(y, z))
                combs.append((eq_str, eq_val))
    return combs


def inverter(data: List[int]) -> List[Tuple[int, int, int]]:
    inverted_data = [-x for x in data]
    res = list(product(*zip(data, inverted_data)))
    return res


# Data to process.
INITIAL_DATA: List[str] = [
    "518-2",
    '533-3',
    # '534-0',
    # '000-3',
    # '000-4'
]
# Available functions.
FUNCTIONS: List[Callable] = [   # the_factorial() removed, see solve().
    plus,
    minus,
    mult,
    div,
    power_to,
    root
]
# Get posible combinations to apply the factor operation.
FACTORS: Set[Tuple] = set(product([1, 0, 0], repeat=3))


def main():
    cases = 0       # Count all possible cases (for each input value).
    data = list()   # List with all final data to be dumped in CSV.
    print("number, solution, number_of_solutions")
    # Iterate over all initial data.
    for eq in INITIAL_DATA:
        # Get values before and after the hyphen.
        nums, res = eq.split('-')
        res = int(res)
        # Get combinations with inverted values.
        combs = inverter([int(n) for n in list(nums)])
        # Iterate over combinations and generate a list with their many possible solutions.
        sol_cnt = 0         # Number of solutions (for each input value).
        solutions = list()  # List with all final data to be dumped in CSV.
        for i in [solve(i, FUNCTIONS) for i in combs]:
            for j in i:
                str_repr, value = j
                # Some values exceed the 4300 digits, hence the 'try-catch'.
                # The function 'sys.set_int_max_str_digits()' may be used instead to increase the str() capabilites.
                try:
                    str(value)
                except ValueError:
                    value = np.inf
                if value == res:
                    sol_cnt += 1
                solutions.append((eq, str_repr, value))
                cases += 1
        # Iterate over all data gathered, and add number of solutions.
        for i in range(len(solutions)):
            eq, str_repr, value = solutions[i]
            solutions[i] += (sol_cnt,)
            print(f"{eq}, {str_repr} = {value}, {sol_cnt}")
        data.extend(solutions)
        # Print all the solutions for this input.
        print(f"\nThese are the {sol_cnt} solutions for input {eq}:")
        solutions = [s for s in solutions if (type(s[2]) is int and s[2] == res)]
        for i in range(len(solutions)):
            print(f"    {i:4}. {solutions[i][1]}")
        print()
    print(f"\nTotal cases: {cases}")

對於 output,請注意解決方案是使用您的函數名稱打印/格式化的,而不是數學運算符。 這只是 output 的摘錄,它使用第 1 位和第 3 位階乘為initial_data中的第一個值生成:

number, solution, number_of_solutions
518-2, plus(plus(5!, 1), 8!) = 40441, 12
518-2, plus(5!, plus(1, 8!)) = 40441, 12      
518-2, plus(minus(5!, 1), 8!) = 40439, 12     
518-2, plus(5!, minus(1, 8!)) = -40199, 12    
518-2, plus(mult(5!, 1), 8!) = 40440, 12      
518-2, plus(5!, mult(1, 8!)) = 40440, 12      
518-2, plus(div(5!, 1), 8!) = 40440, 12       
518-2, plus(5!, div(1, 8!)) = 120, 12
518-2, plus(power_to(5!, 1), 8!) = 40440, 12  
518-2, plus(5!, power_to(1, 8!)) = 121, 12    
518-2, plus(root(5!, 1), 8!) = 40321, 12      
518-2, plus(5!, root(1, 8!)) = 40440, 12

...

These are the 12 solutions for input 518-2:
       0. plus(minus(-5, 1!), 8)
       1. minus(-5, minus(1!, 8))
       2. plus(minus(-5, 1), 8)
       3. minus(-5, minus(1, 8))
       4. minus(-5, plus(1!, -8))
       5. minus(minus(-5, 1!), -8)
       6. minus(-5, plus(1, -8))
       7. minus(minus(-5, 1), -8)
       8. plus(plus(-5, -1), 8)
       9. plus(-5, plus(-1, 8))
      10. plus(-5, minus(-1, -8))
      11. minus(plus(-5, -1), -8)

Total cases: 4608

請注意,僅針對initial_data中的第一個值處理了4608 個案例,因此我建議您先嘗試使用此案例,然后添加 rest,因為對於某些案例,它可能會花費大量處理時間。

另外,我注意到您正在截斷div()root()中的值,因此請記住這一點。 您會在完整的 output 中看到很多naninf ,因為有巨大的值和條件,如div/0 ,所以這是意料之中的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM