嗨,所以我很难弄清楚为什么我的函数会进行除法运算,但是将乘法作为数组保留而没有完成数学运算。这是代码:
const mathObj = {
"*": function(a , b) {return a * b},
"/": function(a , b) {return a / b},
"+": function(a , b) {return a + b},
"-": function(a , b) {return a - b}
}
const arr = [ 10, "/" , 2 , "*" , 10 , "/" , 2 ];
function solveTheMath(arr) {
const len = arr.length;
for(let i = 0 ; i < len ; i++){
if(arr[i] === "/" || arr[i] === "*"){
const sliced = arr.slice(i - 1 , i + 2);
var mathResult = mathObj[arr[i]](sliced[0], sliced[2]);
arr.splice(i - 1 , 3, mathResult);
console.log(arr);
//[5*5]
}
}
}
solveTheMath(arr);
为什么乘法不起作用而除法起作用?
答案 0 :(得分:3)
我的最初答案虽然确实解决了问题,但并不正确。您想通过事物外观使用迭代方法(即使用循环在初始数组中导航并在返回结果之前解决所有操作)。
所以我回复了你
两种操作均有效,问题在于您仅调用一次
solveTheMath
。您需要再次调用函数来解决已构造的数组。如果构造的数组仅由一个元素组成,这意味着过程已到达计算的结尾,则可以返回数组的第一个(也是唯一的元素)。
您正在以递归方式解决问题:
const mathObj = { "*": function(a , b) {return a * b}, "/": function(a , b) {return a / b}, "+": function(a , b) {return a + b}, "-": function(a , b) {return a - b} } const arr = [ 10, "/" , 2 , "*" , 10 , "/" , 2 ]; function solveTheMath(arr) { const len = arr.length; for(let i = 0 ; i < len ; i++){ if(arr[i] === "/" || arr[i] === "*"){ const sliced = arr.slice(i - 1 , i + 2); var mathResult = mathObj[arr[i]](sliced[0], sliced[2]); arr.splice(i - 1 , 3, mathResult); if(arr.length == 1) { return arr[0]; // <- no more calculations needed, return result } else { return solveTheMath(arr); // <- more calculations needed, call it again }; } } } console.log(solveTheMath(arr))
但是实际上这是不正确的,您可以使用两种方法:递归和迭代来解决此问题。我最初的回答提供了一个糟糕的解决方案:我保留了for
循环,并再次调用了该函数来解决数组中剩余的操作。这不是必需的,因为for
循环仅循环查找第二个项目并停止。无论如何,这是一个更清晰的答案,突出了两种方法。
注意:我已将solveTheMath
重命名为calculate
,并将mathObj
重命名为operations
。
这就是您提出问题时所采用的方法。因为您使用for
循环来计算单个函数调用中的所有操作(因此该函数不会一遍又一遍地调用自身)。
为此,我建议使用while
循环,因为**修改arr
时,您将很难循环(每次循环用一个元素替换三个元素)。
我将以数组[10, "/", 2, "*", 10, "/", 2]
作为开始数组,以逐步显示该过程。您可以解决提供的数组的第一个操作。例如,给定:,calculate
将在此处计算第一个操作:10, "/", 2
虽然数组包含多个元素,但我们将执行以下操作:
数组的前三个元素包含:两个因子和一个运算符。通过切片数组,我们可以提取这些值并保存它们。我正在使用destructuring assignment使其更加冗长:
const [a, operator, b] = arr.slice(0, 3);
此处a = 10
,operator = "/"
和b = 2
我们将在此行中计算此操作的结果:
const result = operations[operator](a, b);
result = 5
(参见:10 / 2
)
然后用整数result
替换数组的前三个元素:
arr.splice(0, 3, result);
在这一点上,arr
等于[5, "*", 10, "/", 2]
该块已执行,再次检查while
条件。 arr
确实包含多个元素,因此该块再次被执行。请记住,此时arr
等于[5, "*", 10, "/", 2]
,不等于[10, "/", 2, "*", 10, "/", 2]
(我们正在计算中取得进展)。
在第二个循环的结尾,我们有arr
等于[50, "/", 2]
。
此后等于[25]
的循环。
不再满足while
的条件,因为arr
仅包含一个元素,while
循环已停止并且可以返回结果。
const operations = {
"*": (a, b) => a * b,
"/": (a, b) => a / b,
"+": (a, b) => a + b,
"-": (a, b) => a - b
}
const calculate = arr => {
while(arr.length > 1) { // <- while there are calculations to be done, repeat this block
const [a, operator, b] = arr.slice(0, 3);
const result = operations[operator](a, b);
arr.splice(0, 3, result);
}
return arr[0]; // <- no more operations to be done, return result
}
console.log(calculate(
[10, "/", 2, "*", 10, "/", 2]
));
我们可以使用递归方法:该函数将仅计算所提供数组的第一个操作,并以该第一个操作的结果返回一个新数组。
这里是一个例子:
与迭代数组相同,在给定输入[10, "/", 2, "*", 10, "/", 2]
的情况下,我们首先通过对数组进行切片来获取前两个因子和运算符。然后我们将计算操作结果。最后,我们将结果替换为数组的前三个元素:
const [a, operator, b] = arr.slice(0, 3);
const result = operations[operator](a, b);
arr.splice(0, 3, result);
然后我们检查此数组的长度:
如果仅包含一个元素,则可以返回
否则,如果没有(在我们的例子中),我们将再次调用该函数(这次在[5, "*", 10, "/", 2]
上)。
因此,该函数以新的输入再次运行,并且arr
变为[50, "/", 2]
,其中包含多个元素,因此需要再次调用该函数(以[50, "/", 2]
作为输入)
现在,arr
是[25]
,它仅包含一个元素,可以返回结果(25
)。
const operations = {
"*": (a, b) => a * b,
"/": (a, b) => a / b,
"+": (a, b) => a + b,
"-": (a, b) => a - b
}
const calculate = arr => {
const [a, operator, b] = arr.slice(0, 3);
const result = operations[operator](a, b);
arr.splice(0, 3, result);
if (arr.length == 1) {
return arr[0]; // <- no more calculations needed, return result
} else {
return calculate(arr); // <- more calculations needed, call it again
}
}
console.log(calculate(
[10, "/", 2, "*", 10, "/", 2]
));
您可以看到两种方法都非常相似:主要过程相同,但是它们处理执行结束的方式不同。在这种情况下,两者都可以合理使用。起初,迭代方法对您来说似乎更自然。但是请记住,递归可以使您解决更复杂的问题。例如,如果您想在函数中实现一种括号系统:
您将如何计算:10*(2+2)/2
? calculate([10, "*", 2, "+", 2, "/", 2])
显然会返回11
...
取而代之的是输入[[10, "+", 2], "/", 2]
,这更有意义!我们如何计算正确的结果?
使用我们的递归方法可以很容易地实现:如果a
或/和b
是数组,那么我们通过在它们上调用calculate
来重新分配它们。就是这样:
if(a.constructor == Array) {
a = calculate(a);
}
if(b.constructor == Array) {
b = calculate(b);
}
const operations = {
"*": (a, b) => a * b,
"/": (a, b) => a / b,
"+": (a, b) => a + b,
"-": (a, b) => a - b
}
const calculate = arr => {
let [a, operator, b] = arr.slice(0, 3);
if(a.constructor == Array) {
a = calculate(a);
}
if(b.constructor == Array) {
b = calculate(b);
}
const result = operations[operator](a, b);
arr.splice(0, 3, result);
if (arr.length == 1) {
return arr[0]; // <- no more calculations needed, return result
} else {
return calculate(arr); // <- more calculations needed, call it again
}
}
console.log(calculate(
[[10, "+", 2], "/", 2]
));
在迭代方法的while循环中添加这两个if
块会起作用。但是然后您将得到一个递归函数。这就是为什么您可能想直接使用递归方法的原因。这样一来,您可以更轻松地扩展代码。