Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use set in javaScript

I'm just a beginner in javaScript and have a background of python. I was trying this exercise to check if every character of the string2 is contained within the string1. For example, if string1 is "hello", I'll return true if string2 is "leh" and false if string2 is "low".

What I came up was this:

function mutation(arr) {
  var set = new Set(string1.split(''));
  for (var i = 0; i < string2.length; i++)
    if (!set.has(string2[i]))
      return false;
  return true;
}

I could also go about converting string2 into a set and then do take the difference i.e. the operation of set(string2) - set(string1) which will fetch me the set of characters that are in string2 but not in string1 but I read creating a set is costly so I didn't go ahead.

I checked other solutions and everyone was using string1.indexOf(letter) method for checking if every letter in string2 is there in string1 or not.

I want to know when should one use a set difference. Why everyone is using array.indexOf() method which costs O(n) instead of set.has() method which is O(1). Are there any pitfalls if I'm using set.has(). (say browser compatibility)?

Any recommendation is helpful.

like image 295
Abhinav Srivastava Avatar asked Jul 05 '17 22:07

Abhinav Srivastava


2 Answers

You will find more details and browser compatibility on MDN - Set. For implementation of a Set in general, you can read Set - Implementations on Wikipedia.

Implementations described as "general use" typically strive to optimize the element_of, add, and delete operations.

You can also check some test results on the Array vs Set asnwer on Stack Overflow.


To answer your question, although the has operation might be a bit faster than using String's indexOf (or includes), in your specific case the cost of instantiating a new Set for each comparison is much greater.

I created a simple test with the following two methods:

function existsSet(str1, str2) {
  const set = new Set(str1);
  return ![...str2].some(char => !set.has(char));
}

function existsString(str1, str2) {
  return ![...str2].some(char => !str1.includes(char));
}

I called the above methods for 1 million randomly created strings and I got the following results:

existsSet: 1.29s
existsString: 0.47s

That's almost three times slower for the method that instantiates a Set.


You can find the test I run on the following JsFiddle:

https://jsfiddle.net/mspyratos/zwx3zcx1/11/

like image 176
m.spyratos Avatar answered Oct 19 '22 20:10

m.spyratos


In programming, multiple ways lead to the same solution. Using a set with .has() is just as valid as using indexOf(), it all depends on the surrounding code, and the re-use of the objects (eg: sets) you do.

Usually using indexOf() is faster on the CPU and does not care of the special characters (while a traditional simple split implies that words are separated by always the same character).

Building a set cost a little bit more. But it is still pretty fast so it should not be that much of a consideration.

In the end, do what your instinct tells you to do so that your code stays consistent.

like image 20
Fabien Avatar answered Oct 19 '22 22:10

Fabien