Javascript中是否有切片的替代方法?
我正在使用数组进行计算器项目.我想让用户在找到答案之前编写多个函数,类似于 Casio fx-300ES Plus.现在我正在研究乘法,然后再转向其他运算符.为此,我认为最好的方法是使用 for 循环找到所有x"所在的索引,然后运行另外两个 for 循环,一个查看运算符的左侧,另一个查看右侧其中.一旦它找到另一个运算符,它将中断.然后我可以使用 slice() 将信息存储在x"旁边.
I am working on a calculator project using an array. I wanted to allow the user to write multiple functions before finding the answer, similar to a Casio fx-300ES Plus. Right now I am working on multiplication before moving to other operators. To do this I thought the best way is to find the index at which all 'x' are located using a for-loop, then run two other for-loops, one looking at the left of the operator, the other looking at the right of it. Once it finds another operator, it will break. I could then store the information next to the 'x' using slice().
我遇到的问题是当运算符之间的数字为 1 时.如果我使用 slice() 它不起作用,因为索引之间没有信息.还有其他方法可以将这些数字存储到数组中吗?
The problem I have run in to is when the numbers between operators is 1. If I use slice() it does not work as there is no information between the indexes. Is there another way to store these numbers into an array?
非常感谢任何有关这方面的信息.
Any information on this is much appreciated.
var array = ['7', '3', '+', '6', 'x', '8', '+', '5', '4', 'x', '2'];
//for loop checking for 'x' symbols
for (var i = 0; i < array.length; i++){
console.log("i " + array[i]);
//if there is an 'x'
if (array[i] == 'x') {
console.log('index is at ' + i);
//create an array to eventually store the values
var newArray = new Array();
//checks for the index where j is NaN on the LEFT side
for (j = i - 1; j > 0; --j){
if (isNaN(array[j])){
console.log('j is ' + j);
break;
}
}
//checks for the index where e is NaN on the RIGHT side
for (e = i + 1; e < array.length; e++)
{
if (isNaN(array[e])){
console.log('e is at ' + e);
break;
} else if (e == array.length - 1) {
console.log('e is at array length of ' + e);
break;
}
}
//add the numbers between j and i to newArray
newArray = array.slice(j + 1, i);
console.log(newArray);
//add the numbers between i and e to newArray
newArray = array.slice(i + 1, e);
console.log(newArray);
console.log("array of slice is " + newArray);
}
}
推荐答案
您可以编写 tokenize
来消耗您的文本输入并生成令牌流 -
You could write tokenize
which consumes your text input and produces a stream of tokens -
const input =
[ '7', '3', '+', '6', 'x', '8', '+', '5', '4', 'x', '2' ]
function* tokenize (es) {
let r = 0, n
for (const e of es) {
switch (e) {
case "+":
case "x":
yield { number: r }
yield { operation: e }
r = 0
break
default:
n = Number.parseInt(e, 10)
if (Number.isNaN(n))
throw Error(`unexpected input: ${e}`)
else
r = r * 10 + n
break
}
}
if (r > 0) yield { number: r }
}
for (const t of tokenize(input))
console.log(t)
{"number":73}
{"operation":"+"}
{"number":6}
{"operation":"x"}
{"number":8}
{"operation":"+"}
{"number":54}
{"operation":"x"}
{"number":2}
随后是 parse
,它使用一个标记流并生成一个抽象语法树 -
Followed by parse
which consumes a stream of tokens and produces a abstract syntax tree -
function parse (ts) {
let s = e => e
for (const t of ts) {
if (t?.number) {
let r = s(t)
s = _ => r
}
else if (t?.operation) {
let left = s()
s = right => ({ operation: t.operation, left, right })
}
else {
throw Error(`unexpected token: ${JSON.stringify(t)}`)
}
}
return s()
}
console.log(parse(tokenize(input)))
{
operation: "x",
left: {
operation: "+",
left: {
operation: "x",
left: {
operation: "+",
left: { number: 73 },
right: { number: 6 }
},
right: { number: 8 }
},
right: { number: 54 }
},
right: { number: 2 }
}
最后是 eval
,它将语法树评估为程序 -
Finally eval
which evaluates the syntax tree as a program -
function eval (e) {
if (e?.number)
return e.number
else if (e?.operation)
return evalOp(e)
else
throw Error(`unexpected expression: ${JSON.stringify(e)}`)
}
我们通过单独编写 evalOp
来简化 eval
.这种技术被称为相互递归,对于遍历树状结构非常有效 -
We simplify eval
by writing evalOp
separately. This technique is known as mutual recursion and is super effective for traversing tree-like structures -
function evalOp (e) {
switch (e?.operation) {
case "+": return eval(e.left) + eval(e.right)
case "x": return eval(e.left) * eval(e.right)
default: throw Error(`unexpected operation: ${e.operation}`)
}
}
将 tokenize
、parse
和 eval
放在一起计算结果 -
Bring tokenize
, parse
, and eval
together to compute the result -
const input =
[ '7', '3', '+', '6', 'x', '8', '+', '5', '4', 'x', '2' ]
console.log(eval(parse(tokenize(input))))
1372
当使用袖珍计算器的运算顺序进行评估时,这是正确的 -
This is correct when evaluated using pocket calculator order of operations -
73
... + 6 = 79
... * 8 = 632
... + 54 = 686
... * 2 = 1372
如果您想使用不同的操作顺序(即 PEMDAS)进行评估,则必须重写 parse
以将令牌流解释为不同的程序.
If you wanted to evaluate using a different order of operations, ie PEMDAS, you would have to rewrite parse
to interpret the stream of tokens as a different program.
展开下面的代码片段以在您的浏览器中验证结果 -
Expand the snippet below to verify the result in your browser -
const input =
[ '7', '3', '+', '6', 'x', '8', '+', '5', '4', 'x', '2' ]
function* tokenize (es) {
let r = 0, n
for (const e of es) {
switch (e) {
case "+":
case "x":
yield { number: r }
yield { operation: e }
r = 0
break
default:
n = Number.parseInt(e, 10)
if (Number.isNaN(n))
throw Error(`unexpected input: ${e}`)
else
r = r * 10 + n
break
}
}
if (r > 0) yield { number: r }
}
function parse (ts) {
let s = e => e
for (const t of ts) {
if (t?.number) {
let r = s(t)
s = _ => r
}
else if (t?.operation) {
let left = s()
s = right => ({ operation: t.operation, left, right })
}
else {
throw Error(`unexpected token: ${JSON.stringify(t)}`)
}
}
return s()
}
function eval (e) {
if (e?.number)
return e.number
else if (e?.operation)
return evalOp(e)
else
throw Error(`unexpected expression: ${JSON.stringify(e)}`)
}
function evalOp (e) {
switch (e?.operation) {
case "+": return eval(e.left) + eval(e.right)
case "x": return eval(e.left) * eval(e.right)
default: throw Error(`unexpected operation: ${e.operation}`)
}
}
console.log(eval(parse(tokenize(input))))
相关文章