Javascript 高效获取二维数组中某个值的行号

Javascript efficiently get row number of a value in two dimensional array

return 二维数组中值的行号的最有效方法是什么?例如,我可以执行以下操作。我可以使用 map and/or 过滤器而不是迭代来做到这一点吗?

function getRow(array2d = [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']], value = 'g') {
  for (let i = 0; i < array2d.length; i++) {
    if (array2d[i].indexOf(value) > -1) {
      return i;
    }
  }
  return -1;
}

您可以这样使用 Array.prototype.findIndex with Array.prototype.includes

function getRow(array2d = [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']], value = 'g') {
  for (let i = 0; i < array2d.length; i++) {
    if (array2d[i].indexOf(value) > -1) {
      return i;
    }
  }
  return -1;
}

const now = performance.now();
console.log(getRow());
console.log(performance.now() - now);

function getRow(array2d = [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']], value = 'g') {
  return array2d.findIndex(x => x.includes(value));
}

const now = performance.now();
console.log(getRow());
console.log(performance.now() - now);

在此处发布 findIndex 的示例,回调速度比 for loop..

我的结果:

for 循环 = 11.020000092685223 更快。

带回调的 findIndex = 12.699999962933362 较慢。

故事的士气,如果表演很关键,总是考验。浏览器有一些非常聪明/复杂的优化。例如,@GuerricP 发布的基准仅进行了简单的 属性 比较,而 V8 引擎可能会检测到这一点。放个更复杂的includes进去,就是另外一回事了

同样出于上述原因,您永远不应该预先优化 JS,只有在您认为有性能问题需要解决时才进行优化。

同样使事情复杂化的是不同的浏览器/OS可能会给出不同的结果。我的测试 Linux / Chrome.

function getRow(array2d = [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']], value = 'g') {
  for (let i = 0; i < array2d.length; i++) if (array2d[i].indexOf(value) > -1) return i;
  return -1;
}

const now = performance.now();
for (let l = 0; l < 1000000; l += 1)
  getRow();
console.log(performance.now() - now);

function getRow(array2d = [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']], value = 'g') {
  return array2d.findIndex(x => x.includes(value));
}

const now = performance.now();
for (let l = 0; l < 1000000; l += 1)
  getRow();
console.log(performance.now() - now);

有了节点,可以把数组分成多个 子数组并使用异步 运行 并行搜索:

下面的脚本使用了两个线程,给你一半的时间。

async function aGetRow(d, v) {
  let half = Math.floor(d.length / 2);
  let remain = d.length - half
  let r = await Promise.all([
    getRow(d.slice(0, half), v),
    getRow(d.slice(half, remain), v),
  ]);
  if (r[0] != -1) {
    return r[0];
  }
  if (r[1] != -1) {
    return r[1];
  }
  return -1;
}

需要注意的是,NodeJS默认在线程池中有4个线程。如果拆分数组多于线程,则不会获得性能提升。

编辑:对于对 NodeJS 线程和事件循环的细节感兴趣的人,我强烈推荐这个视频:https://youtu.be/zphcsoSJMvM