最终我想接受这个:
2x + 3 = 5
并解决x,首先从两侧减去3,所以2x = 2
,然后将两边除以2,所以x = 1
。我正在考虑如何在JavaScript中创建这样的函数,以便按顺序返回一系列步骤,包括结果。显然,“eval”不会为此做任何事情,所以看起来似乎必须重新创建方程式。
我最初想到的是,忽略X,并尝试创建一个可以解决简单方程的函数,而不需要eval或任何内置函数。
我认为第一步是使用.split分解术语,但我遇到了一些问题,因为我需要拆分多个符号。例如,假设我有简单的表达式来评估:3 - 6 * 3 / 9 + 5
。因此,在我们进入操作顺序之前,仅仅拆分每个术语(并对它们进行分类)是困难的部分,这是我此时的主要具体问题。
我开始只是一个接一个地拆分,但我遇到了一些问题,特别是考虑到了订单。
function solve(eq) {
var minuses = eq.split("-"),
pluses = minuses.map(x=> x.split("+")),
timeses = pluses.map(x=>x.map(y=>y.split("*"))),
dividers = timeses.map(x=>x.map(y=>y.map(z=>z.split("/"))));
console.log(minuses, pluses, timeses, dividers);
}
solve("3 - 6 * 3 / 9 + 5");
正如您所看到的,对于每个连续的运算符,我需要映射前一个运算符中的每个元素以将其拆分,然后我留下了一个数组数组等...
那么1)如何更有效地分割这些术语,而不为每个术语创建一个新变量,并手动递归映射每个术语?看起来我应该只有一些数组字典跟踪操作顺序(现在不考虑括号或指数):["*","/","+","-"]
- 并且给定该数组,生成类似于上例中的最后一个数组(“dividers”)它只包含常量,并以某种方式跟踪每个存储的数组遵循的元素...
2)如何给出值数组的表达式?
我只是对逻辑有点困惑,我想我需要从最后一个数组开始处理并一次解决一个常量,跟踪哪个运算符是当前运算符,但我不确定究竟是什么。
您可以通过以下步骤执行此操作:
split()
并将+
和-
分开,这将在乘法和除法之后发生。map()
和split()
上再次使用阵列上的*
和/
。sovleSingle
并执行加法和减法。只要没有括号()
,该函数与eval的作用相同。
注意:这在+
和-
中首先出现或者首先出现在*
和/
中并不重要。但*,/
应该在+,-
之前发生
function solveSingle(arr){
arr = arr.slice();
while(arr.length-1){
if(arr[1] === '*') arr[0] = arr[0] * arr[2]
if(arr[1] === '-') arr[0] = arr[0] - arr[2]
if(arr[1] === '+') arr[0] = +arr[0] + (+arr[2])
if(arr[1] === '/') arr[0] = arr[0] / arr[2]
arr.splice(1,1);
arr.splice(1,1);
}
return arr[0];
}
function solve(eq) {
let res = eq.split(/(\+|-)/g).map(x => x.trim().split(/(\*|\/)/g).map(a => a.trim()));
res = res.map(x => solveSingle(x)); //evaluating nested * and / operations.
return solveSingle(res) //at last evaluating + and -
}
console.log(solve("3 - 6 * 3 / 9 + 5")); //6
console.log(eval("3 - 6 * 3 / 9 + 5")) //6
虽然您的问题不需要构建,但binary expression tree是集思广益解决数学查询的逻辑的好方法。
因此,对于查询3 - 6 * 3 / 9 + 5
,代表性二进制表达式树是:
plus
|_minus
| |_3
| |_divide
| |_times
| | |_3
| | |_6
| |_9
|_5
要解决上面的树,你递归地从叶级到根解决。
同样,您不需要构建树。它只是帮助我们在这里看到解析的逻辑:
鉴于上述逻辑,这是一个实现:
function solve(str) {
var expressionIndex = Math.max(str.lastIndexOf("-"), str.lastIndexOf("+"));
if (expressionIndex === -1) {
expressionIndex = Math.max(str.lastIndexOf("*"), str.lastIndexOf("/"));
}
if (expressionIndex === -1) {
var num = Number.parseInt(str.trim());
if (isNaN(num)) {
throw Exception("not a valid number");
} else {
return num;
}
} else {
var leftVal = solve(str.substring(0, expressionIndex).trim());
var rightVal = solve(str.substring(expressionIndex + 1).trim());
switch (str[expressionIndex]) {
case "+":
return leftVal + rightVal;
case "-":
return leftVal - rightVal;
case "*":
return leftVal * rightVal;
case "/":
return leftVal / rightVal;
}
}
}
function parse(str) {
var expressionIndex = Math.max(str.lastIndexOf("-"), str.lastIndexOf("+"));
if (expressionIndex === -1) {
expressionIndex = Math.max(str.lastIndexOf("*"), str.lastIndexOf("/"));
}
if (expressionIndex === -1) {
var num = Number.parseInt(str.trim());
if (isNaN(num)) {
throw Exception("not a valid number");
} else {
return { type: "number", value: num };
}
} else {
var leftNode = parse(str.substring(0, expressionIndex).trim());
var rightNode = parse(str.substring(expressionIndex + 1).trim());
return {
type: "expression",
value: str[expressionIndex],
left: leftNode,
right: rightNode
};
}
}
console.log(solve("3 - 6 * 3 / 9 + 5"));
console.log(parse("3 - 6 * 3 / 9 + 5"));
以上是非常简单查询的解决方案,只有+, - ,*,/(没有括号,例如)。对于像你的第一个例子那样求解方程式需要更多的工作。
编辑:添加一个解析函数来返回树。