简体   繁体   中英

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

What is the most efficient way to return the row number of a value in a two-dimensional array? For example, I could do the following. Can I do it using map and/or filter instead of iteration?

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

You could use Array.prototype.findIndex with Array.prototype.includes like this:

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

Posting example here of findIndex with callback been slower than for loop ..

Results for me:

for loop = 11.020000092685223 faster.

findIndex with callback = 12.699999962933362 slower.

The morale of the story, if performance is critical always test. Browsers have some very clever / complicated optimisation. For example the benchmark posted by @GuerricP only did a simple property comparison and the V8 engine possible detects this. Place a more complicated includes inside, and it's a different story.

It's also for the above reason you should never pre-optimise JS, only optimise when you believe you have a performance issue to solve.

Also to complicate matter different Browsers / OS's will likely give different results. My tests where 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);

With nodes, you can divide the array into multiple sub-arrays and use async to run the search in parallel:

The following script uses two threads and will give you half of the time.

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

One must note that NodeJS has 4 threads in the thread pool by default. If you split the array more than the threads, you will not gain performance enhancement.

Edit: For people interested in the details of NodeJS threading and event loop, I highly recommend this video: https://youtu.be/zphcsoSJMvM

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM