【问题标题】:Improve performance of a JavaScript function (with an array lookup)提高 JavaScript 函数的性能(使用数组查找)
【发布时间】:2016-06-09 15:17:51
【问题描述】:

我正在尝试完成一个代码挑战,我必须将手机 t9 输入的击键解码为字符以创建文本消息。主函数(reverse_t9)接受一串键,例如“44 444”或“999337777”,我需要将它们翻译成相应的文本(分别为“hi”或“yes”)。

我的所有逻辑都已关闭,可以生成正确的输出,但挑战是告诉我我超过了 4000 毫秒的时间限制。我找到了几个可以提高性能的地方,但仍然无法达到这个标准。我认为最浪费时间的是我的“getLetterFromDigits”函数,它必须遍历我的数组才能找到一组击键的对应映射。

我是否遗漏了其他一些明显的性能问题?如果您需要更多信息,请告诉我。

function reverse_t9(keys) {
    var retVal = "";
    var maxKeystrokes = 3;
    var splitKeystrokes = splitKeystrokesBySpacesAndKeys(keys);

    for (i = 0, numSplits = splitKeystrokes.length; i < numSplits; i++){
        //console.log("THIS SPLIT:");
        //console.log(splitKeystrokes[i]);
        //console.log("THIS LETTER:");
        //console.log(getLetterFromDigits(splitKeystrokes[i]));
        retVal = retVal + getLetterFromDigits(splitKeystrokes[i]);
    }

    return retVal;
}

function splitKeystrokesBySpacesAndKeys(keys) {
    var retVal = [];
    var lastKey = "";
    var thisKey = "";
    var lastSplit = 0;
    var isSpace = 0;

    for (i = 0, numKeys = keys.length; i <= numKeys; i++) {

        thisKey = keys.substring(i, i + 1);

        if (i == 0) {
            // FIRST TIME AROUND, DO NOTHING ELSE, JUST ASSIGN LAST KEY
            lastKey = thisKey;
        } else {
            if (thisKey != lastKey) {
                if (thisKey != " ") {
                    if (lastKey != " ") {
                        retVal.push(keys.substring(lastSplit, i));
                    } else {
                        retVal.push(keys.substring(lastSplit, i - 1));
                    }

                    lastSplit = i;
                }

                lastKey = thisKey;

            } else {
                // KEY DID NOT CHANGE, ASSIGN LAST KEY AND CONTINUE ON
                lastKey = thisKey;
            }
        }
    }

    return retVal;
}

function getLetterFromDigits(digits){
    var retVal;

    var digitMapping = [
    {
        digit: "1",
        mapping: []
    },
    {
        digit: "2",
        mapping: ["a", "b", "c"]
    },
    {
        digit: "3",
        mapping: ["d", "e", "f"]
    },
    {
        digit: "4",
        mapping: ["g", "h", "i"]
    },
    {
        digit: "5",
        mapping: ["j", "k", "l"]
    },
    {
        digit: "6",
        mapping: ["m", "n", "o"]
    },
    {
        digit: "7",
        mapping: ["p", "q", "r", "s"]
    },
    {
        digit: "8",
        mapping: ["t", "u", "v"]
    },
    {
        digit: "9",
        mapping: ["w", "x", "y", "z"]
    },
    {
        digit: "0",
        mapping: ["*"]
    }

    ];

    var digit = digits.substring(0, 1);


    for (i = 0, numMappings = digitMapping.length; i < numMappings; i++){
        if (digitMapping[i].digit == digit){
            retVal = digitMapping[i].mapping[digits.length - 1];
            break;
        }
    }

    return retVal;
}

【问题讨论】:

  • 一方面,您可以创建一个简单的数组,而不是像那样设置映射列表的键。您正在映射字符串“0”到“9”——这是一个简单的数组查找。只需制作一个数组数组。
  • 另外,您可以查看keys.charAt(i) 或简单的keys[i] 是否更快,而不是keys.substring(i, i+1)
  • 哎呀...不知道 codereview。 @Pointy 你的意思是: var digitMapping = [['a','b','c'],['d','e','f']...]; ?
  • 我能发现的最大问题是您忘记在所有三个循环中使用vari 变量声明为本地变量。这很可能是运行时间极短的原因,尽管您一定很幸运仍然看到它 a) 终止和 b) 得到正确的结果。

标签: javascript arrays performance


【解决方案1】:

首先,在函数之外声明您的数字映射,这样您就可以重用该工作的结果,而不是每次调用该函数时都执行该工作。

其次,让digitMapping 使用键/值对,这样您就可以根据给定的属性名称进行快速查找,而不必遍历它。

var digitMapping = 
{
    "1": [],
    "2": ["a", "b", "c"],
    ...
};

function getLetterFromDigits(digits){
    var digit = digits.substring(0, 1);
    return digitMapping[digit][digits.length - 1];
}

【讨论】:

  • 这似乎是一个很好的解决方案 - 让我尝试一下并回复您。
  • @xboxremote:起初它是不正确的(可能仍然不正确),但希望它能给你正确的想法。
  • 我认为它确实......仍在努力,但我明白了。
  • 这成功了。我必须添加映射为 0 的“空格键”字符才能使其工作,我最终取消了键/值对,只是做了一个数组数组:var digitMapping = [ [" "], [], ["a", "b", "c"], ["d", "e", "f"], ["g", "h", "i"], ["j", "k", "l"], ["m", "n", "o"], ["p", "q", "r", "s"], ["t", "u", "v"], ["w", "x", "y", "z"] ];
【解决方案2】:

几个指针:

  1. 将长度保存在变量中并使用它。使用 Array.length 将检查每次迭代。
  2. 创建 1 个映射对象,而不是对象数组,例如:
{
  "1": [],
  "2": ["a", "b", "c"]
},

并将其获取为digitMapping[mapping[digits.length - 1]]

  1. 除了thisKey = keys.substring(i, i + 1);,您可以将字符保存在char_arr = keys.split("") 之类的变量中并循环遍历它。
  2. 您可以摆脱 1 次迭代(第一次迭代)。只需设置lastKey = char_arr[0]lastKey=keys.charAt(0)
  3. if (thisKey != lastKey) 的其他部分不是必需的。如果两个值相同,则不需要设置lastKey = thisKey;

【讨论】:

    【解决方案3】:

    试试我的版本。

    function getMsg(val){
      //split digits to array
      val = val.split('');
      //some internal vars
      var letter = [];
      var last = val[0];
      var msg='';
      for(var i=0,n=val.length;i<n;i++){
        if(val[i]==last)
          //collect sequential digits
          letter.push(val[i]);
        else{
          //new digit 
          msg += digMap[letter[0]][letter.length-1];
          //reinit letter array
          letter=[val[i]];
          last = val[i];
        }
      }
      msg += digMap[letter[0]][letter.length-1];
      return msg; //return decoded
    }
    //map digits as @Rajesh recommended
    var digMap={
      "1":[" "],
      "2":'abc'.split(''),
      "3":'def'.split(''),
      "4":'ghi'.split(''),
      "5":'jkl'.split(''),
      "6":'mno'.split(''),
      "7":'pqrs'.split(''),
      "8":'tuv'.split(''),
      "9":'wxyz'.split(''),
      "0":["*"],
      " ":['']
    }
    //test functionality
    console.time('txt');
    console.log(getMsg('999337777'));
    //yes
    console.timeEnd('txt');
    

    【讨论】:

      猜你喜欢
      • 2018-12-12
      • 2019-12-26
      • 2015-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多