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

more efficient way of searching 2D array - break after match?

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

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

我的代码通过拉取随机提示然后将它们洗牌到数组 (sm1) 来创建基于研究了哪些单元的评估。

其中一些提示有与之关联的图像文件,所有提示都有音频文件。这些媒体文件的文件名基于它们在我们 material 中出现的位置,例如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]

至于效率嘛,我不太确定,但至于在比赛中破门,其实很简单。

你可以做到的一种方法(可能也是最好的方法)是将它放在一个函数中,然后 return 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;
          }
        }
      }
    }
  }
}

如果您不适合使用某个函数,则可以内联完成(后面是骇人听闻的代码;您已被警告过)。

尽管 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;
        }
      }
    }
  }
}

一般来说,循环遍历数组最高效的方法是使用array.forEach,不幸的是,调用break是无法短路Array.forEach的。 How to short circuit Array.forEach like calling break?。但在这种情况下,您可以使用其他方法,例如 array.some() 来代替。

如果我必须实施您的项目,我不会使用二维数组,因为它的效率低于一维数组。我会按如下方式使用数组:

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