0

Doing Hackerrank challenges and looked up a faster solution to a problem than my current one. My understanding of .map and .filter is that they are both O(n) functions. But when executing using filter and map is way faster than two for loops. Why is that?

For reference: My two for loop implementation:

function matchingStrings(strings, queries) {
   let countArr = new Array(queries.length).fill(0);
   let index = 0;
   for(const queryStr of queries){
      for(const findStr of strings){
          if(queryStr === findStr){
              countArr[index] += 1;
          }
      }
   index++;
   }
   return countArr;
}

Much faster filter and map implementation (from https://gist.github.com/rahul4coding/64023e39017f0a5915a9ff884d18446d)

function matchingStrings(strings, queries) {

    return queries.map(x=>strings.filter(y=>y===x).length)

}
  • This could be [branch prediction](https://stackoverflow.com/a/11227902/112968). Try replacing `if (queryStr === findStr) countArr[index] += 1;` with `countArr[index] += queryStr === findStr;`. Without your input, I'm unable to reproduce, so this is just a guess. If that doesn't work, maybe `++countArr[index]`? – knittl May 15 '22 at 18:23
  • Both of your functions have the same algorithmic time complexity (`O(n*m)`, where `n` is the number of queries and `m` is the number of strings). But that doesn't say anything about performance. – Bergi May 15 '22 at 19:08
  • 2
    What input are you testing with? What runtime are you using? What exactly is "*way faster*"? – Bergi May 15 '22 at 19:10

1 Answers1

0

Without the dataset it's a bit hard to replicate the problem, but I've created a test program to run both the functions and there doesn't seem to much difference. Sometimes the nested for loops are faster.

const queriesT = ["foo0", "foo1", "foo2", "foo3", "foo4", "foo5",
                  "foo6", "foo7", "foo8", "foo9", "foo10", "foo11", "foo12",
                  "foo13", "foo14", "foo15", "foo16", "foo17", "foo18", "foo19",];

const testStrs = [ "foo1", "foo1", "foo5", "foo19", "foo14", "foo2", "foo15", "foo19",
                   "foo2", "foo10", "foo18", "foo16", "foo14", "foo2", "foo15", "foo19",
                   "foo5", "foo12", "foo6", "foo17", "foo14", "foo2", "foo15", "foo19",
                   "foo1", "foo9", "foo10", "foo7", "foo14", "foo2", "foo15", "foo19"];

function matchingStrings() {
   let countArr = new Array(queriesT.length).fill(0);
   let index = 0;
   for(const queryStr of queriesT){
      for(const findStr of testStrs){
          if(queryStr === findStr){
              countArr[index] += 1;
          }
      }
   index++;
   }
   return countArr;
}

function matchingStrings2(strings, queries) {
  
    return queriesT.map(x=>testStrs.filter(y=>y===x).length);

}

function testFunc(func){
  
  const ms = new Date().getTime();
  
  const r = func();
  
  console.log("result: " + r);
  
  const msA = new Date().getTime();
  
  console.log("Time (ms): " + (msA - ms));
  
}

testFunc(matchingStrings);
testFunc(matchingStrings2);
KoderM
  • 382
  • 2
  • 15