Javascript中是否有切片的替代方法? [英] Is there an alternative to slice in Javascript?

查看:20
本文介绍了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}`)
  }
}

tokenizeparseeval 放在一起计算结果 -

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))))

这篇关于Javascript中是否有切片的替代方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆