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.")
Answer from snowfrogdev on Stack OverflowOk, 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.")
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
When to Use ES6 Sets Instead of Arrays in JavaScript
performance - Why is array.includes an order of magnitude faster than set.has in javascript? - Stack Overflow
javascript - Should I use Array or Set if both can be used to finish my task? - Software Engineering Stack Exchange
ecmascript 6 - Javascript set vs array vs object definition - Stack Overflow
JavaScript Sets wont make you a better person, but they could improve your project.
The use of either Array or Set by your function is equivalent: You create a container, and you push stuff into it. This leaves two areas for consideration:
What does the consumer need to do with the container?
Which container is more efficient (space or time)?
If you find that the consumer just iterates over the container, both Array and Set are equivalent again from this usage perspective. However, if your user needs to answer the question "is this index in the container?", then Set is the only appropriate container type.
Once you have asserted that the container type is indeed irrelevant to use, both on the producer and consumer side, go for the more efficient container:
Arrayshould be implemented as a simple slap of contiguous memory that holds (the references to) its elements. Apush()generally means 1) checking for space (one comparison), 2) appending the new element to the end of the buffer, and 3) updating the length field.Setis required to ensure that its elements are unique. That is, whereArray.push()is happy to push an element twice,Set.insert()must somehow catch this condition and handle it. This requires extra work. To getO(1)performance,Setwould normally be implemented as a hash table. Hash tables are fast, but they are definitely more complex than a simple, contiguous buffer. Thus,Set.insert()will generally have to do significantly more work thanArray.push(), and its data structures are very likely to consume more memory.
Both space and time efficiency are better for Array than for Set. And this is why I would default to using Array over Set whenever their use is equivalent.
From what you have shown in your question, it does not matter (and consider to refactor your code in case it starts to matter).
not limited to this case, if I found both Array and Set can finish my task, should I use Array or Set
Producing an Array or a Set is typically not an end in itself, it is a means to an end, so often you can find out what the caller of your method which produces this result might prefer.
Note, if you start using an array, and it turns out for further processing a Set would be beneficial (or you need both, the array and the set representation), you can easily convert it:
let resultSet = new Set(results)
I am not a Javascript expert, but I would expect the conversion the other way round to require at a little bit more code. Thus, if in doubt, I personally would start with an array first, and switch to a set if it fits better, but that is somewhat opinionated.
Every value in a set has to be unique, but in Array you can push same value as many times as you'd like.
"Set objects are collections of values. You can iterate through the elements of a set in insertion order. A value in the Set may only occur once; it is unique in the Set's collection." https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
Removing values, interestingly enough, when dealing with small amounts of data, there isn't much performance difference between the two (Array and Set), but when you start to deal with big data, removal is a lot faster in Sets vs Arrays.
Adding values to Array is 4 times faster than adding them to set.
Iterating through the values Array is here also better performer (Growing exponentially based on the amount of data).
You can read more about the performance differences at; Javascript Set vs. Array performance
"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."
Count unique items in object Set Vs Object write-up https://github.com/anvaka/set-vs-object
TL:DR Set is almost two times faster than Object.
Why Set was introduced (My guess)?
There are sometimes when you need an easy way to build up a collection of values and you have to make sure each value is unique. This brings a lot overhead away from the old fashioned check if array has the value or not and then push or skip.
This scenario was not covered in the performance post I linked earlier, but doing fast experiment on Array of 10,000 items and then adding 15 items where 5 were duplicates to the combined collection, adding to array with checking for duplicate values and skipping if duplicate it took 74ms and with set just using the set.add(value) it took 9ms.
When would you need this?
One real life example that came to my mind is that if you have an email marketing letter and you for example would have options; - TV - Music - Movies - Sports
One day your client or you would like to have only one email option for TV, Music and Movies called "Entertainment". You would need to build up a new collection based on the data from these 3 different values and you would need to make sure each email are added to the new entertainment emailing list only once. Meaning that users could've opted-in for Movies as well as TV if they are interested in both.
Here you could just make set Entertainment and then iterate through all the lists TV/Music/Movies and use Entertainment.add(email) and the set would take care of skipping values that already exists in the list. Hence avoiding duplicate emails in the emailing list.
Also set would be optimal format to store your email subscriber addresses, as nobody could accidentally opt-in twice for you emails.
Basically, set is used to store elements uniquely whereas in arrays, you can duplicate the elements. And regarding objects, in use cases when you also need to store additional information regarding each element, then you would choose object over set and array.
For example: storing info. of your apps users, which include their name, phone no., address, email etc. Then in objects, you can define a key, let's say email (or you could also create a unique id), then keys in your object would be email (or the other one) and the additional info about the user would get stored as properties.