🌐
Brian Douglass
bhdouglass.com › home › blog › node.js performance: array.includes vs set.has
Node.js Performance: Array.includes vs Set.has | Brian Douglass
December 14, 2024 - However, if you have an array and want to convert it to a set to use Set.has() you probably shouldn’t. Unless that array is very large and you need to do a large number of lookups on the array, it is probably not worth the cost to initialize the set. However, (again) if you know you need to do lookups on an array and you can create a set instead of creating an array, then you might want to consider doing that to reap the faster lookup times of Set.has().
🌐
MeasureThat
measurethat.net › Benchmarks › Show › 7818 › 0 › sethas-vs-arrayincludes
Benchmark: set.has vs. array.includes - MeasureThat.net
Array includes vs Set.has · Comments · × · Do you really want to delete benchmark? Cancel Delete · × · FAQ: FAQ · Source code: GitHub/MeasureThat.net · Report issues: MeasureThat.net/Issues · Based on: Benchmark.js · Facebook page: https://www.facebook.com/MeasureThat.Net ·
Discussions

Conversion of large array to a Set seems slow
Bug Description A discussion came up in my company about the performance benefits of set.has over array.includes (eslint rule). I was interested if these performance benefits translated over to Her... More on github.com
🌐 github.com
5
January 16, 2024
I discovered Set exists for the first time today... Is it really faster?
I use sets, maps, and spread syntax all the time. I’ve never “done the math” to see the specs of the speed for sets. Maps have methods that are way faster when trying to search and filter things in big data sets. More on reddit.com
🌐 r/learnjavascript
26
11
July 24, 2024
Set.has() and Array.includes() should narrow the type of their argument to the type of this when they return true
My compilation target is ES2022 and my lib is the default · Set.has() and Array.includes() should narrow the type of their argument to the type of this when they return true (which implies they should accept wider types as arguments) More on github.com
🌐 github.com
8
November 29, 2022
javascript - Time complexity of array.prototype.includes vs. set.prototype.has - Stack Overflow
I've been reading conflicting answers about modern javascript engines' time complexity when it comes to sets vs arrays in javascript. I completed the demo task of codility, which is a simple assign... More on stackoverflow.com
🌐 stackoverflow.com
🌐
DEV Community
dev.to › programminginblood › why-sethas-is-faster-than-arrayincludes-for-finding-items-4hh
Why Set.has() is Faster Than Array.includes() for Finding Items - DEV Community
November 1, 2024 - For example, while checking if ... On the other hand, Array.includes() examines each element from left to right sequentially until it may either find the item of interest or reaches its very end....
🌐
DEV Community
dev.to › arnaud › using-array-prototype-includes-vs-set-prototype-has-to-filter-arrays-41fg
Using Array.prototype.includes() vs Set.prototype.has() to filter arrays - DEV Community
July 2, 2020 - Then we're going to run two tests: one using includes, and one using has, and we're going to start with LENGTH at 10, and increase it every time, as my premise is that for small array it won't matter much, but we want to see WHEN it starts mattering: // filter using includes console.time("includes"); valuesToTest.filter((v) => valuesToKeep.includes(v)); // n2 console.timeEnd("includes"); // filter using has console.time("has"); const valuesToKeepSet = new Set(valuesToKeep); valuesToTest.filter((v) => valuesToKeepSet.has(v)); // n console.timeEnd("has");
🌐
GitHub
github.com › facebook › hermes › issues › 1253
Conversion of large array to a Set seems slow · Issue #1253 · facebook/hermes
January 16, 2024 - ** Testing small array/set: Array.includes start 1705422981216 Array.includes end 1705422981216 array.includes difference: 0 set conversion 4 set.has start 1705422981220 set.has end 1705422981220 set.has difference: 0 ** Testing medium array/set: Array.includes start 1705422981220 Array.includes end 1705422981221 array.includes difference: 1 set conversion 54 set.has start 1705422981275 set.has end 1705422981275 set.has difference: 0 ** Testing large array/set: Array.includes start 1705422981275 Array.includes end 1705422981281 array.includes difference: 6 set conversion 1160 set.has start 1705422982441 set.has end 1705422982441 set.has difference: 0
Author: facebook
🌐
Reddit
reddit.com › r/learnjavascript › i discovered set exists for the first time today... is it really faster?
r/learnjavascript on Reddit: I discovered Set exists for the first time today... Is it really faster?
July 24, 2024 -

I was working through a problem in Angular, and finally had all the data I wanted to process pieced together.

I am very curious whether Set() is a common thing these days and whether I should consider learning more about these ES6 operator even if nobody on my team has ever used them (I have the least experience by a mile).

My first instinct was to go for an array, but then I asked ChatGPT to help me finish up the code, and it switched to a Set(). When I asked why, it said Set() is faster and excludes duplicates from the array.

The task consisted of:

Array 1: An array of arrays (a ton of data inside them),
Array 2: An array of 2+ objects with some string properties
Array 3: An array of objects with about 90 objects in it

The purpose is:

  1. Loop through each object of Array 1 and find if the status string is what we want. If so we add the ID from that object to the targetId's Set().

  2. Use the list of 90 objects and check if the ID we added in Step 1 exists in an object somewhere in there

  3. If it exists in there, use the item.category to access the number value from categoryCounts object and increment it.

Here is a generic version of the code:

const categoryCounts: {
[category: string]: number
} = {};
// Extract IDs from the data
const targetIds = new Set < number > ();
const segments = [
...data.segmentOneArray,
...data.segmentTwoArray,
...data.segmentThreeArray,
...data.segmentFourArray,
];
segments.forEach((segment) => {
if (segment.status === "statusWeWant" && segment.itemId) {
targetIds.add(segment.itemId);
}
});
// Process the item list to count occurrences for each category
itemList.forEach(item => {
if (targetIds.has(Number(item.itemId))) {
const category = item.category;
if (filteredCategories.some(c => c.description === category)) {
if (!categoryCounts[category]) {
categoryCounts[category] = 0;
}
categoryCounts[category]++;
}
}
})

🌐
Medium
medium.com › @yuri-lima › javascript-performance-when-set-becomes-faster-than-array-includes-0adb3134f95b
JavaScript Performance: When Set Becomes Faster Than Array.includes() | by Yuri Lima | Medium
January 31, 2025 - If you’re doing occasional, one-off lookups in small datasets, .includes() is fine. But if you need to check for values multiple times, especially in large datasets, always use ************Set.has(). It scales much better and prevents performance bottlenecks. 🚨 If you care about preserving order, Set is not a replacement for an array.
🌐
GitHub
github.com › microsoft › TypeScript › issues › 51678
Set.has() and Array.includes() should narrow the type of their argument to the type of this when they return true · Issue #51678 · microsoft/TypeScript
November 29, 2022 - My compilation target is ES2022 and my lib is the default · Set.has() and Array.includes() should narrow the type of their argument to the type of this when they return true (which implies they should accept wider types as arguments)
Author: microsoft
🌐
Jsbench
jsbench.me › myjyq4ixs1 › 1
Array includes VS Object address VS Set has (version 1)
JSBench.me is a JavaScript performance benchmarking playground based on Benchmark.js and influenced by JSPerf.
Find elsewhere
🌐
Kilian Valkhof
kilianvalkhof.com › home › javascript › includes, contains or has. finding things in iterables (lists) in javascript
Includes, contains or has. Finding things in iterables (lists) in JavaScript | Kilian Valkhof
February 17, 2022 - We can split JavaScript into two parts: language features and DOM APIs. Both of these are made/designed by different groups of people: language features by ECMA and DOM APIs essentially by browser vendors. classList is a DOM api whereas Array, Set and Map are all language features, which could explain the difference between classList and the rest. It still doesn’t explain why Array uses includes and Sets and Maps use has.
🌐
Jsbench
jsbench.me › myjyq4ixs1 › 2
Array includes VS Object address VS Set has (version 2) - JavaScript benchmark at JSBench.me
i += ary.includes(3333) && 1; i += ary.includes(1234) && 1; i += strAry.includes('x3333') && 1; i += strAry.includes('x1234') && 1;DEFER · ready · i += set.has(3333) && 1; i += set.has(1234) && 1; i += strSet.has('x3333') && 1; i += strSet.has('x1234') && 1;DEFER · Test Case - click to add another test case · teardown JavaScript ·
🌐
MeasureThat
measurethat.net › Benchmarks › Show › 23556 › 0 › arrayincludes-vs-sethas
Benchmark: Array.includes() vs Set.has() - MeasureThat.net
November 19, 2024 - More information: Monitoring JavaScript Memory ... User agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 · Browser/OS: Chrome 137 on Windows View result in a separate tab Embed ... LLMs can make mistakes. Check important info. ... Set.has vs. Array.includes
Top answer
1 of 3
6

I know this is an old question, but I was double checking the data. I too assumed Set.has would be O(1) or O(log N), but in my first test, it appeared to be O(N). The specs for these functions hint as much, but are quite hard to decipher: https://tc39.es/ecma262/#sec-array.prototype.includes https://tc39.es/ecma262/#sec-set.prototype.has Elsewhere, though, they also say that Set.has must be sublinear-- and I believe modern implementations are.

Empirically, Set.has demonstrates linear performance when I ran it in some code playgrounds... but in real environments like node and chrome, they there were no surprises. I'm not sure what the playground was running on the back end, but perhaps a Set polyfill was used. So be careful!

Here's my test cases, trimmed down to remove the randomness:

const makeArray = (size) => [...Array(size)].map(() => size);

const small =  makeArray(1000000);
const medium = makeArray(10000000);
const large =  makeArray(100000000);

const solution1 = arr => {
  console.time('Array.includes');
  arr.includes(arr.length - 1)
  console.timeEnd('Array.includes');
}

const solution2 = arr => {
  const set = new Set(arr)
  console.time('Set.has');
  set.has(arr.length-1)
  console.timeEnd('Set.has');
}


console.log('** Testing small array:');
solution1(small);
solution2(small);
console.log('** Testing medium array:');
solution1(medium);
solution2(medium);
console.log('** Testing large array:');
solution1(large);
solution2(large);

In Chrome, though:

** Testing small array:
VM183:10 Array.includes: 1.371826171875 ms
VM183:17 Set.has: 0.005859375 ms
VM183:25 ** Testing medium array:
VM183:10 Array.includes: 14.32568359375 ms
VM183:17 Set.has: 0.009765625 ms
VM183:28 ** Testing large array:
VM183:10 Array.includes: 115.695068359375 ms
VM183:17 Set.has: 0.0048828125 ms

In Node 16.5:

Testing small array:
Array.includes: 1.223ms
Set.has: 0.01ms
Testing medium array:
Array.includes: 11.41ms
Set.has: 0.054ms
Testing large array:
Array.includes: 127.297ms
Set.has: 0.047ms

So, yeah, Arrays are definitionly linear, and Sets are much faster.

2 of 3
2

The comparison like that is not entirely fair because in the function where you use the Set, the Array needs to be converted to a Set first, which takes some time.

Have a look at the results below if this is ignored. I have updated the solution2 function to receive a Set and changed the while loop to a for loop - for the sake of direct comparison.

You may notice that for a small array, Set might be slower. This is trivial because the time complexity only really comes into affect for a large (significant) n.

Also note, Array.includes is indeed O(n) but because it is in a for loop which in the worst case could go up to n the solution has a time complexity of O(n^2).

const rand = (size) => [...Array(size)].map(() => Math.floor(Math.random() * size));

const small = rand(100);
const medium = rand(5000);
const large = rand(100000);

const solution1 = arr => {
  console.time('Array.includes');
  for (let int = 1;;int++) {
    if (!arr.includes(int)) {
      console.timeEnd('Array.includes');
      return int;
    }
  }
}

const solution2 = set => {
  console.time('Set.has');
  for (let i = 1;;i++) {
    if (!set.has(i)) {
      console.timeEnd('Set.has');
      return i
    }
  }
}

console.log('Testing small array:');
solution1(small);
solution2(new Set(small));
console.log('Testing medium array:');
solution1(medium);
solution2(new Set(medium));
console.log('Testing large array:');
solution1(large);
solution2(new Set(large));
Run code snippetEdit code snippet Hide Results Copy to answer Expand

🌐
MDN Web Docs
developer.mozilla.org › en-US › docs › Web › JavaScript › Reference › Global_Objects › Set › has
Set.prototype.has() - JavaScript - MDN Web Docs
The has() method of Set instances returns a boolean indicating whether the specified value exists in this Set or not.
🌐
Jsperf
jsperf.app › pikuzu
Set.has() vs Array.includes()
Set.has() vs Array.includes() - Online Javascript Benchmark
Top answer
1 of 7
182

Ok, I have tested adding, iterating and removing elements from both an array and a set. I ran a "small" test, using 10 000 elements and a "big" test, using 100 000 elements. Here are the results.

Adding elements to a collection

It would seem that the .push array method is about 4 times faster than the .add set method, no matter the number of elements being added.

Iterating over and modifying elements in a collection

For this part of the test I used a for loop to iterate over the array and a for of loop to iterate over the set. Again, iterating over the array was faster. This time it would seem that it is exponentially so as it took twice as long during the "small" tests and almost four times longer during the "big" tests.

Removing elements from a collection

Now this is where it gets interesting. I used a combination of a for loop and .splice to remove some elements from the array and I used for of and .delete to remove some elements from the set. For the "small" tests, it was about three times faster to remove items from the set (2.6 ms vs 7.1 ms) but things changed drastically for the "big" test where it took 1955.1 ms to remove items from the array while it only took 83.6 ms to remove them from the set, 23 times faster.

Conclusions

At 10k elements, both tests ran comparable times (array: 16.6 ms, set: 20.7 ms) but when dealing with 100k elements, the set was the clear winner (array: 1974.8 ms, set: 83.6 ms) but only because of the removing operation. Otherwise the array was faster. I couldn't say exactly why that is.

I played around with some hybrid scenarios where an array was created and populated and then converted into a set where some elements would be removed, the set would then be reconverted into an array. Although doing this will give much better performance than removing elements in the array, the additional processing time needed to transfer to and from a set outweighs the gains of populating an array instead of a set. In the end, it is faster to only deal with a set. Still, it is an interesting idea, that if one chooses to use an array as a data collection for some big data that doesn't have duplicates, it could be advantageous performance wise, if there is ever a need to remove many elements in one operation, to convert the array to a set, perform the removal operation, and convert the set back to an array.

Array code:

var timer = function(name) {
  var start = new Date();
  return {
    stop: function() {
      var end = new Date();
      var time = end.getTime() - start.getTime();
      console.log('Timer:', name, 'finished in', time, 'ms');
    }
  }
};

var getRandom = function(min, max) {
  return Math.random() * (max - min) + min;
};

var lastNames = ['SMITH', 'JOHNSON', 'WILLIAMS', 'JONES', 'BROWN', 'DAVIS', 'MILLER', 'WILSON', 'MOORE', 'TAYLOR', 'ANDERSON', 'THOMAS'];

var genLastName = function() {
  var index = Math.round(getRandom(0, lastNames.length - 1));
  return lastNames[index];
};

var sex = ["Male", "Female"];

var genSex = function() {
  var index = Math.round(getRandom(0, sex.length - 1));
  return sex[index];
};

var Person = function() {
  this.name = genLastName();
  this.age = Math.round(getRandom(0, 100))
  this.sex = "Male"
};

var genPersons = function() {
  for (var i = 0; i < 100000; i++)
    personArray.push(new Person());
};

var changeSex = function() {
  for (var i = 0; i < personArray.length; i++) {
    personArray[i].sex = genSex();
  }
};

var deleteMale = function() {
  for (var i = 0; i < personArray.length; i++) {
    if (personArray[i].sex === "Male") {
      personArray.splice(i, 1)
      i--
    }
  }
};

var t = timer("Array");

var personArray = [];

genPersons();

changeSex();

deleteMale();

t.stop();

console.log("Done! There are " + personArray.length + " persons.")

Set code:

var timer = function(name) {
    var start = new Date();
    return {
        stop: function() {
            var end  = new Date();
            var time = end.getTime() - start.getTime();
            console.log('Timer:', name, 'finished in', time, 'ms');
        }
    }
};

var getRandom = function (min, max) {
  return Math.random() * (max - min) + min;
};

var lastNames = ['SMITH','JOHNSON','WILLIAMS','JONES','BROWN','DAVIS','MILLER','WILSON','MOORE','TAYLOR','ANDERSON','THOMAS'];

var genLastName = function() {
    var index = Math.round(getRandom(0, lastNames.length - 1));
    return lastNames[index];
};

var sex = ["Male", "Female"];

var genSex = function() {
    var index = Math.round(getRandom(0, sex.length - 1));
    return sex[index];
};

var Person = function() {
	this.name = genLastName();
	this.age = Math.round(getRandom(0,100))
	this.sex = "Male"
};

var genPersons = function() {
for (var i = 0; i < 100000; i++)
	personSet.add(new Person());
};

var changeSex = function() {
	for (var key of personSet) {
		key.sex = genSex();
	}
};

var deleteMale = function() {
	for (var key of personSet) {
		if (key.sex === "Male") {
			personSet.delete(key)
		}
	}
};

var t = timer("Set");

var personSet = new Set();

genPersons();

changeSex();

deleteMale();

t.stop();

console.log("Done! There are " + personSet.size + " persons.")

2 of 7
94

OBSERVATIONS:

  • Set operations can be understood as snapshots within the execution stream.
  • We are not before a definitive substitute.
  • The elements of a Set class have no accessible indexes.
  • Set class is an Array class complement, useful in those scenarios where we need to store a collection on which to apply basic addition, Deletion, checking and iteration operations.

I share some test of performance. Try to open your console and copypaste the code below.

Creating an array (125000)

var n = 125000;
var arr = Array.apply( null, Array( n ) ).map( ( x, i ) => i );
console.info( arr.length ); // 125000

1. Locating an Index

We compared the has method of Set with Array indexOf:

Array/indexOf (0.281ms) | Set/has (0.053ms)

// Helpers
var checkArr = ( arr, item ) => arr.indexOf( item ) !== -1;
var checkSet = ( set, item ) => set.has( item );

// Vars
var set, result;

console.time( 'timeTest' );
result = checkArr( arr, 123123 );
console.timeEnd( 'timeTest' );

set = new Set( arr );

console.time( 'timeTest' );
checkSet( set, 123123 );
console.timeEnd( 'timeTest' );

2. Adding a new element

We compare the add and push methods of the Set and Array objects respectively:

Array/push (1.612ms) | Set/add (0.006ms)

console.time( 'timeTest' );
arr.push( n + 1 );
console.timeEnd( 'timeTest' );

set = new Set( arr );

console.time( 'timeTest' );
set.add( n + 1 );
console.timeEnd( 'timeTest' );

console.info( arr.length ); // 125001
console.info( set.size ); // 125001

3. Deleting an element

When deleting elements, we have to keep in mind that Array and Set do not start under equal conditions. Array does not have a native method, so an external function is necessary.

Array/deleteFromArr (0.356ms) | Set/remove (0.019ms)

var deleteFromArr = ( arr, item ) => {
    var i = arr.indexOf( item );
    i !== -1 && arr.splice( i, 1 );
};

console.time( 'timeTest' );
deleteFromArr( arr, 123123 );
console.timeEnd( 'timeTest' );

set = new Set( arr );

console.time( 'timeTest' );
set.delete( 123123 );
console.timeEnd( 'timeTest' );

Read the full article here

🌐
Sergio Carracedo
sergiocarracedo.es › js-lists-performance
Sergio Carracedo | Find a item in lists in js: Performance of Set vs Array
September 4, 2023 - Rather than array that stores the values in memory, Set uses a Hashtable that is intrinsically faster than an array to find a value, as as we mentioned the Big O average is O(1)
🌐
GitHub
github.com › anvaka › set-vs-object
GitHub - anvaka/set-vs-object: What is faster Set or Object? · GitHub
function similarityObject(objA, objB) { var aKeys = Object.keys(objA); var intersect = 0; aKeys.forEach(function(key) { if (objB[key]) intersect += 1; }); var objBSize = Object.keys(setB).length; var objASize = aKeys.length; var similarity = intersect / (objASize + objBSize - intersect); return similarity; } function similaritySet(setA, setB) { var intersect = 0; setA.forEach(function(key) { if (setB.has(key)) intersect += 1; }); var similarity = intersect / (setA.size + setB.size - intersect); return similarity; }
Author: anvaka
🌐
Jsbench
jsbench.me › v0m6mrvwq4 › 1
Array.includes vs Set.has for small arrays (version 1)
JSBench.me is a JavaScript performance benchmarking playground based on Benchmark.js and influenced by JSPerf.