numpy 对列表中所有可能的数字组合执行算术计算

fcg9iug3  于 2022-12-04  发布在  其他
关注(0)|答案(1)|浏览(112)

我创建的数据格式如下:

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时遇到了麻烦,目前这只适用于一个示例,并返回了一个中间带有函数对象的难看的读数。
先谢谢你。

mpbci0fu

mpbci0fu1#

我认为这会对你有很大的帮助(调整是你),但它没有写在CSV,我留给你去尝试,只是考虑到有成千上万的可能组合,在某些情况下,结果真的很大(见main()中的评论)。
我在函数声明中添加了缺少的类型,以便清晰和成功linting(与旧的Python版本兼容)。此外,我认为不需要函数combinations(),所以我删除了它。在我提出的代码中,函数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}")

对于输出,请注意,解是使用函数名而不是数学运算符来打印/格式化的。这只是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

请注意,4608个案例仅针对initial_data中的第一个值进行了处理,因此我建议您先尝试使用此案例,然后再添加其余案例,因为对于某些案例,这可能会花费大量处理时间。
另外,我注意到您截断了div()root()中的值,所以请记住这一点。您将在完整输出中看到大量的naninf,因为有大量的值和条件,如div/0,所以这是意料之中的。

相关问题