Let's say I have these four numbers: [1, 5, 3, 8]. And I want to check which of the math operations equals to 10. Also the order of the numbers matters, meaning the first number should always be the first index in the array and so on.
For example:
How can I achieve this?
Honestly, I have no idea how I should approach this. So any help would be greatly appreciated.
We create an Expr class to represent expressions, which consist of two operands (which may be simple numbers or other expressions) and an operator. This provides convenience functions for evaluating the expression and outputting the expression as a string.
In the simple case, where there are only two expressions x and y, we return all possible combinations x+y, x-y, x*y, x÷y.
Then, when there are more expression operands, we find (all combinations of (x operator y) with ...z), and (x operator (all combinations of y with ...z))
class Op {
constructor(symbol,func) { this.symbol = symbol; this.func = func; }
invoke(x,y) { return this.func(
x instanceof Expr ? x.eval() : x,
y instanceof Expr ? y.eval() : y)
}
toString() { return this.symbol }
}
const ops = [
new Op('+', (x,y)=>x+y), new Op('-', (x,y)=>x-y),
new Op('*', (x,y)=>x*y), new Op('÷', (x,y)=>x/y),
]
class Expr {
constructor(x,op,y){ this.x=x; this.op=op; this.y=y }
eval() { return this.op.invoke(this.x, this.y) }
toString() { return `(${this.x}${this.op}${this.y})` }
}
const f = (x,y,...z) =>
!z.length ? ops.map(op=>new Expr(x,op,y)) :
[...f(x,y).flatMap(expr=>f(expr, ...z)),
...f(y,...z).flatMap(expr=>f(x, expr))]
// show all combinations
console.log(f(...[1, 5, 3, 8]).map(i=>i.toString()))
// show only combinations that evaluate to 10
console.log(f(...[1, 5, 3, 8]).filter(i=>i.eval()===10).map(i=>i.toString()))