更有效的搜索2D数组的方法 - 匹配后中断?

时间:2017-07-06 07:47:47

标签: javascript arrays loops multidimensional-array break

我有一个学生正在学习的2D单元阵列。对于每个单元,他们正在研究不同数量的功能(也称为目标),并且对于每个功能,可以在评估中询问不同数量的提示。我的数据是2D数组:

functions = [
  ["Unit 1",
    [ // function 1
      "prompt 1",
      "prompt 2",
      ...,
      "prompt n"],
    [ // function 2
  etc...

我的代码根据已经研究过的单位创建评估,方法是拉随机提示,然后将这些单元混合到数组中(sm1)。

其中一些提示具有与之关联的图像文件,并且都具有音频文件。这些媒体文件的文件名基于它们在我们的材料中出现的位置,例如: u1f1p1.mp3

所以我的解决方案是通过根据数组中的位置创建文件名来匹配这种规律性。这是我的代码:

for (var a = 0; a < sm1.length; a++) {// for each of sm1's prompts
    for (var b = 0; b <= functions.length-6; b++) { // limit it to units 1-3 of 8 for this specific assessment
       for(var c = 1; c < functions[b].length; c++) { // for each unit's function but starting at 1 to skip "Unit x" label at this point in the array
           for (var d = 0; d < functions[b][c].length; d++) { // for each prompt for each function for each unit
               if(functions[b][c][d] === sm1[a]) { // see if it matches
                    fileNames.push('u'+(b+1)+'f'+c+'p'+(d+1)); // create file name from index and add to fileNames[]
                }
            }
        }
    }
} 

此代码工作正常,因为速度实际上与我们的目的无关,我可以说完成了工作。但是,我知道这必然是无效的,因为这不仅是一个很长的循环,而且即使在找到匹配后它仍会继续运行。

所以,有两个问题:

  1. 找到匹配的最有效方法是什么?
  2. 如果找到sm1[n],我该如何休息并继续寻找sm1[n+1]

2 个答案:

答案 0 :(得分:1)

至于效率,我不确定,但至于打破比赛,它实际上非常简单。

你能做到的一种方式(可能是最好的方法)是把它放在一个函数中,当你找到你的匹配时返回fileNames -

function findFileName(sm1, functions, fileNames) {
  for (var a = 0; a < sm1.length; a++) { // for each of sm1's prompts
    for (var b = 0; b <= functions.length - 6; b++) { // limit it to units 1-3 of 8 for this specific assessment
      for (var c = 1; c < functions[b].length; c++) { // for each unit's function but starting at 1 to skip "Unit x" label at this point in the array
        for (var d = 0; d < functions[b][c].length; d++) { // for each prompt for each function for each unit
          if (functions[b][c][d] === sm1[a]) { // see if it matches
            fileNames.push('u' + (b + 1) + 'f' + c + 'p' + (d + 1)); // create file name from index and add to fileNames[]
            return fileNames;
          }
        }
      }
    }
  }
}

如果你没有使用某个函数,它可以内联完成(后面是hacky代码;你已经被警告了)。

虽然for语句的第二个子句通常依赖于第一个子句(a < sm1.length),但实际上并没有什么能阻止你在那里放置与第一个子句无关的额外约束。所以你可以在每次迭代的第一次for检查之前添加一个布尔变量,并在找到匹配时将其设置为true -

var matchFound = false;
for (var a = 0; a < sm1.length && !matchFound; a++) { // for each of sm1's prompts
  for (var b = 0; b <= functions.length - 6 && !matchFound; b++) { // limit it to units 1-3 of 8 for this specific assessment
    for (var c = 1; c < functions[b].length && !matchFound; c++) { // for each unit's function but starting at 1 to skip "Unit x" label at this point in the array
      for (var d = 0; d < functions[b][c].length && !matchFound; d++) { // for each prompt for each function for each unit
        if (functions[b][c][d] === sm1[a]) { // see if it matches
          fileNames.push('u' + (b + 1) + 'f' + c + 'p' + (d + 1)); // create file name from index and add to fileNames[]
          matchFound = true;
        }
      }
    }
  }
}

答案 1 :(得分:0)

通常,循环数组的最有效方法是使用array.forEach,遗憾的是,不可能将Array.forEach调用break断开。 How to short circuit Array.forEach like calling break?。但在这种情况下,您可以使用另一种方法,例如array.some()。

如果我必须实现你的项目,我不会使用2D数组,因为它的效率低于1D数组。我会按如下方式使用数组:

let a = [];

a["prompt 1"] = {name: "tom", age: 15, unit: 1} // You can put all your infos in your objects
a["prompt 2"] = {name: "bob", age: 42, unit: 2}
a["prompt 3"] = {name: "alex", age: 55, unit: 3}
a["prompt 4"] = {name: "homer", age: 50, unit: 3}

let b = ["prompt 2", "prompt 4"]

b.forEach((key)=>{ // for each element of array b

    if(a[key] !== undefined) // one match found
    {
        // fileNames.push('u'+(b+1)+'f'+c+'p'+(d+1));
        console.log(a[key])
    }
})