数字列表上所有可能的操作组合,以查找特定的数字

时间:2019-03-15 17:20:47

标签: python python-3.x numbers combinations

我知道还有其他问题,例如我的,但唯一的问题是,它们获得了列表中所有变量的所有组合,但我想要这样,以便用户输入所需数量和所需数量制作所需的数字。这是我的代码:

numbers = []
operators = ['+', '*', '-', '/']
desire = int(input("Enter the number you want: "))
num1 = int(input("Enter First number: "))
num2 = int(input("Enter Second number: "))
num3 = int(input("Enter Third number: "))
num4 = int(input("Enter Fourth number: "))
numbers.append(num1)
numbers.append(num2)
numbers.append(num3)
numbers.append(num4)

但是我不知道该如何扩展

这是代码应做的示例:

说他们要拨打的电话号码是24

说他们输入的数字是1, 9, 8, 2

输出应为:

9 - 1 + 8 * 2 = 24

等...

所有可能的解决方案都必须列出

所有建议都将被采纳

4 个答案:

答案 0 :(得分:2)

您可以使用itertools模块中的置换以所有可能的方式将数字和运算符排列到字符串公式中。然后使用eval()计算结果。

例如:

from itertools import permutations
numbers   = ["1","9","8","2"]
target    = 24
operators = ["+","-","*","/"]
for values in permutations(numbers,len(numbers)):
    for oper in permutations(operators,len(numbers)-1):
        formula = "".join(o+v for o,v in zip([""]+list(oper),values))
        if eval(formula) == target: print(formula,"=",target)

[UPDATE1] (如果您被允许多次使用同一个运算符(如对1 + 1 + 1 * 8 = 24的评论所建议),则需要使用groups_with_replacement来生成更多的操作员模式:

from itertools import permutations,combinations_with_replacement
numbers   = ["1","1","1","8"]
target    = 10
operators = ["+","-","*","/"]
seen      = set()
for values in permutations(numbers,len(numbers)):
    for operCombo in combinations_with_replacement(operators,len(numbers)-1):
        for oper in permutations(operCombo,len(numbers)-1):
            formula = "".join(o+v for o,v in zip([""]+list(oper),values))
            if formula not in seen and eval(formula) == target:
                print(formula,"=",target)
                seen.add(formula)

从本质上讲,这与上一个示例的不同之处仅在于插入了for operCombo in ...循环。

注意:组合将生成看起来完全相同的公式,因此您将要避免打印已经看到的解决方案(就像我在这里所做的那样)。如果在输入中重复输入任何数字,则在前面的示例中也会发生重复。

还要注意,为了使9-1 + 8 * 2产生24,必须在加法和减法之前(即在优先规则下)执行乘法,否则9-1 + 8 * 2 = 32。您需要支持括号以涵盖不同的操作顺序。

[UPDATE2] 支持括号的内容要多一些,具体取决于您要允许多少个数字。对于4个数字,共有11种模式:

  • 不带括号:A + B + C + D
  • A + B组:(A + B)+ C + D
  • B + C组:A +(B + C)+ D
  • C + D组:A + B +(C + D)
  • A + B和C + D组:(A + B)+(C + D)
  • A + B + C组:(A + B + C)+ D
  • B + C + D组:A +(B + C + D)
  • A + B组+ C:((A + B)+ C)+ D
  • A + B + C组:(A +(B + C))+ D
  • B + C组+ D:A +(((B + C)+ D)
  • B + C + D组:A +(B +(C + D))

如果您有4个以上的数字,则会有更多的括号分组方式。

这是一个示例(包含4个数字):

from itertools import permutations,combinations_with_replacement
numbers   = ["9","8","1","2"]
target    = 24
operators = ["+","-","*","/"]
groups    = ['X+X+X+X', 'X+X+(X+X)', 'X+(X+X)+X', '(X+X+X)+X', '(X+X)+X+X', 'X+(X+X+X)', '((X+X)+X)+X', 'X+(X+(X+X))', 'X+((X+X)+X)', '(X+X)+(X+X)', '(X+(X+X))+X']
seen      = set()
for values in permutations(numbers,len(numbers)):
    for operCombo in combinations_with_replacement(operators,len(numbers)-1):
        for oper in permutations(operCombo,len(numbers)-1):
            formulaKey = "".join(oper+values)
            if formulaKey in seen: continue # ignore variations on parentheses alone
            for pattern in groups:
                formula = "".join(o+p for o,p in zip([""]+list(oper), pattern.split("+")))
                formula = "".join(v+p for v,p in zip([""]+list(values),formula.split("X")))
                try:
                    if eval(formula) == target:
                        print(formula,"=",target)
                        seen.add(formulaKey)
                        break 
                except: pass

分组可能导致被零除,因此必须添加try:except块。

这将产生以下结果:

9*8/(1+2) = 24
9+8*2-1 = 24
9*8/(2+1) = 24
9-1+8*2 = 24
9-(1-8*2) = 24
9-1+2*8 = 24
(9-1)*2+8 = 24
9/(1+2)*8 = 24
9/((1+2)/8) = 24
9-(1-2*8) = 24
9+2*8-1 = 24
9/(2+1)*8 = 24
9/((2+1)/8) = 24
8+(9-1)*2 = 24
8*9/(1+2) = 24
8*9/(2+1) = 24
8-(1-9)*2 = 24
8/(1+2)*9 = 24
8/((1+2)/9) = 24
8+2*(9-1) = 24
8*2+9-1 = 24
8*2-1+9 = 24
8/(2+1)*9 = 24
8/((2+1)/9) = 24
8-2*(1-9) = 24
8*2-(1-9) = 24
2*(9-1)+8 = 24
2*8+9-1 = 24
2*8-1+9 = 24
2*8-(1-9) = 24

要为更多数字生成括号分组模式,可以使用以下功能:

from itertools import product
import re
def groupPatterns(count,pattern=None):
    arr = pattern or "X"*count
    if len(arr) < 2 : return [arr]
    result = []
    for mid in range(1,len(arr)):
        leftPattern  = groupPatterns(count,arr[:mid])
        rightPattern = groupPatterns(count,arr[mid:])
        for left,right in product(leftPattern,rightPattern):
            result += [left + right]
            if len(left)  > 1 : result += ["(" + left + ")" + right]
            if len(right) > 1 : result += [left + "(" + right + ")"]
            if len(left) > 1 and len(right) > 1: 
                result += ["(" + left + ")(" + right + ")"]
    if pattern: return result # recursion
    patterns = [] # final, add "+" between X value placeholders or groups
    for pat in sorted(set(result),key=lambda x:len(x)):
        pat = re.sub("X(?=X)", r"X+",  pat)  # XX --> X+X
        pat = re.sub("X\(",    r"X+(", pat)  # X( --> X+(
        pat = re.sub("\)X",    r")+X", pat)  # )X --> )+X
        pat = re.sub("\)\(",   r")+(", pat)  # )( --> )+(
        patterns.append(pat)
    return patterns

然后在上一个示例中将groups = ["X+X+X+X",...替换为groups = groupPatterns(len(numbers))

或者,为任意数量的值创建一个完全通用的函数,无论是否进行分组和运算符重用:

from itertools import permutations,combinations_with_replacement
def numbersToTarget(numbers,target,reuseOper=True,allowGroups=True,operators=["+","-","*","/"]):   
    groups      = groupPatterns(len(numbers)) if allowGroups else [ "+".join("X"*len(numbers)) ]
    seen        = set()
    for values in permutations(numbers,len(numbers)):
        for operCombo in combinations_with_replacement(operators,len(numbers)-1) if reuseOper else [operators]:
            for opers in permutations(operCombo,len(numbers)-1):
                formulaKey = str(opers)+str(values)
                if formulaKey in seen: continue # ignore variations on parentheses alone
                for pattern in groups:
                    formula = "".join(o+p      for o,p in zip([""]+list(opers), pattern.split("+")))
                    formula = "".join(str(v)+p for v,p in zip([""]+list(values),formula.split("X")))
                    try:
                        if eval(formula) == target:
                            seen.add(formulaKey)
                            yield formula
                            break 
                    except: pass

for formula in numbersToTarget([9,8,1,2],24):
    print("24 =",formula)
for formula in numbersToTarget([9,8,1,2,5],0,allowGroups=False):
    print("0 =",formula)

答案 1 :(得分:1)

这是我想到的使用Dialog对数学运算符的字符串进行数学计算的结果(请注意,这不是一种非常安全的方法,恶意用户可能会通过它来入侵您的程序。如果您进行部署,则可能看Evaluating a mathematical expression in a string

eval()

我的第一个简单测试

numbers = []
operators = ['+', '*', '-', '/']
desire = int(input("Enter the number you want: "))
num1 = input("Enter First number: ")
num2 = input("Enter Second number: ")
num3 = input("Enter Third number: ")
num4 = input("Enter Fourth number: ")
numbers.append(num1)
numbers.append(num2)
numbers.append(num3)
numbers.append(num4)

for operator1 in operators:
    for operator2 in operators:
        for operator3 in operators:
            problem = numbers[0] + operator1 + numbers[1] + operator2 + numbers[2] + operator3 + numbers[3]
            result = int(eval(problem))
            if result == desire:
                print("{} = {}".format(problem, result))

收益

  

10 + 10 + 10 + 10 = 40

更复杂的测试

Enter the number you want: 40
Enter First number: 10
Enter Second number: 10
Enter Third number: 10
Enter Fourth number: 10

产量:

  

6 * 3 + 4-4 = 18

     

6 * 3 * 4/4 = 18

     

6 * 3-4 + 4 = 18

     

6 * 3/4 * 4 = 18

     

6/3 + 4 * 4 = 18

请注意,尽管此解决方案并未考虑您的电话号码的各种顺序。我会看看我能否制作出更狡猾的东西

更新

我还设计了一种方法来考虑数字的所有排列

Enter the number you want: 18
Enter First number: 6
Enter Second number: 3
Enter Third number: 4
Enter Fourth number: 4

现在测试

def make_order_combinations():
    number_orders = []
    for i in range(4):
        for j in range(4):
            for k in range(4):
                for z in range(4):
                    if i != j and i != k and i != z and j != k and j != z and k != z:
                        number_orders.append((i, j, k, z))
    return number_orders


def solve_given_number_order(number_order):
    for operator1 in operators:
        for operator2 in operators:
            for operator3 in operators:
                problem = numbers[number_order[0]] + operator1 + numbers[number_order[1]] + operator2 + numbers[number_order[2]] + operator3 + numbers[number_order[3]]
                # print(problem)
                result = eval(problem)
                # print(result)
                if result == desire:
                    print("{} = {}".format(problem, result))

numbers = []
operators = ['+', '*', '-', '/']
desire = int(input("Enter the number you want: "))
num1 = input("Enter First number: ")
num2 = input("Enter Second number: ")
num3 = input("Enter Third number: ")
num4 = input("Enter Fourth number: ")
numbers.append(num1)
numbers.append(num2)
numbers.append(num3)
numbers.append(num4)

list_of_orders = make_order_combinations()
for order in list_of_orders:
    solve_given_number_order(order)

收益

Enter the number you want: 67
Enter First number: 15
Enter Second number: 4
Enter Third number: 7
Enter Fourth number: 1

在您可以看到的地方,也确实考虑了所有可能的数字重排。操作顺序仍然适用,因此输出:

  

1 * 7 + 4 * 15 = 67

应解读为(1 * 7)+(4 * 15)= 67

答案 2 :(得分:1)

这确实没有经过很好的测试(可能会做很多工作),但可能会让您入门:

from operator import mul, add, sub, truediv
from itertools import permutations, combinations_with_replacement

operators = (mul, add, sub, truediv)
desire = 24

numbers = [1, 9, 8, 2]

OP2SYM = {mul: '*', add: '+', sub: '-', truediv: '/'}

for op0, op1, op2 in combinations_with_replacement((mul, add, sub, truediv), 3):
    for n0, n1, n2, n3 in permutations(numbers, 4):
        # print(op0, op1, op2)
        # print(n0, n1, n2, n3)
        if op0(n0, op1(n1, op2(n2, n3))) == desire:
            print('{} {} ({} {} ({} {} {}))'.format(
                n0, OP2SYM[op0], n1, OP2SYM[op1], n2, OP2SYM[op2], n3))
        if op0(op1(n0, n1), op2(n2, n3)) == desire:
            print('({} {} {}) {} ({} {} {})'.format(
                n0, OP2SYM[op0], n1, OP2SYM[op1], n2, OP2SYM[op2], n3))
        if op2(op1(op0(n0, n1), n2), n3) == desire:
            print('(({} {} {}) {} {}) {} {}'.format(
                n0, OP2SYM[op0], n1, OP2SYM[op1], n2, OP2SYM[op2], n3))

它输出

((8 * 2) + 9) - 1
((2 * 8) + 9) - 1

一个更简单的想法是构造'6*3-4+4'形式的字符串并使用ast.literal_eval对其求值

答案 3 :(得分:1)

您可以尝试使用 itertools

中的置换模块
public function index()
{
    return new GeneralResource(/model/::all());
}

public function show(/model/ $model)
{
    return new GeneralResource($model);
}

public function store(/model/Request $request)
{
    try {
        $model = /model/::create($request->validated());
        return response()->json(['status' => 'success']);
    } catch (\Exception $e) {
        echo $e->getMessage();
    }
}

public function update(/model/Request $request, /model/ $model)
{
    try {
        $model->update($request->validated());
        return response()->json(['status' => 'success']);
    } catch (\Exception $e) {
        echo $e->getMessage();
    }
}

public function destroy(/model/ $model)
{
    try {
        $model->delete();
        return response()->json(['status' => 'success']);
    } catch (\Exception $e) {
        echo $e->getMessage();
    }
}