Using the 'set' data structure

May-29-2023

Learning JavaScript we all begin using the simple object: {}. Straightforward to declare and to use, and on top of this, it is (almost) the same syntax than JSON objects. But in ES6 were introduced new data structures which are slightly optimized. You may not find a use case for these, but it’s always better to know in the case of an interview 😉

The Set data structure

The Set object is a optimized (but dumbed-dowm) version of an Array. So basically,

  • You can insert into a Set objects of any type.
  • You can iterate through a Set, the order will be the order in which the components were inserted
  • You can test whether an element is inside a Set or not, and this will be quicker than if you used an Array.
  • However, Very useful array methods are not implemented: no .filter, .map, .find etc. .forEach works though.
  • You cannot access the element at the ith position.
  • To derive an Array from a set, use const myArray = Array.from(mySet).

A little test…

All this would be very formal and theoretical - now let’s see if we can find a difference.

You will find at the end a short program which measures the time to put 10,000 random numbers into each structure, and then tries to retrieve 10,000 elements and see how much time it takes.

In a code sandbox I got results with the routine with Array taking roughly 150ms, but the Set never taking more than 1ms! 🤯 This being said:

  • The problem is very specific and plays to the advantage of the Set, as it is clearly written that the retrieval is very fast.
  • We cannot change the order of elements in a Set, so the use cases are very specific.

But if you are in a situation where you use an Array for a queue (i.e. always inserting at the end) and you just care to know if an element is inside the array or not, think about using a Set, the program perfomance will be greatly enhanced!

function compareResults() {
  const TEST_SIZE = 10_000;

  // First test -> with an array
  const a0 = performance.now();
  const myArray = [];  
  // let's push random elements in an array
  for (let i = 0; i < TEST_SIZE; i++) {
    const element = Math.floor(Math.random() * 10 * TEST_SIZE);
    myArray.push(element);
  }
  performance.mark("arrayAfterInit");
  // Let's try to retrieve the same number of random elements
  let matchesInArray = 0;
  for (let i = 0; i < TEST_SIZE; i++) {
    const element = Math.floor(Math.random() * 10 * TEST_SIZE);
    if (myArray.find((x) => x === element)) {
      matchesInArray = matchesInArray + 1;
    }
  }
  const a1 = performance.now();
  console.log(`Array: ${a1 - a0} (${matchesInArray})`);

  // ----------------------------------
  // Second test -> with a Set
  const s0 = performance.now();
  const mySet = new Set();
  // let's insert random elements into the Set
  for (let i = 0; i < TEST_SIZE; i++) {
    const element = Math.floor(Math.random() * 10 * TEST_SIZE);
    mySet.add(element);
  }
  let matchesInSet = 0;
  // let's try to retrieve random elements from the Set
  for (let i = 0; i < TEST_SIZE; i++) {
    const element = Math.floor(Math.random() * 10 * TEST_SIZE);
    if (mySet.has(element)) {
      matchesInSet = matchesInSet + 1;
    }
  }
  const s1 = performance.now();

  console.log(`Set: ${s1 - s0} (${matchesInSet})`);
}