Sets in JavaScript — the only explanation you will ever need
Tags: javascript, webdev
Published: 2021-05-16 00:27:11

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z79llshi4gsh46c2wye6.png)
###This post contains technical information, code examples and real use cases.
  
# Introduction  
## What Sets are in general?  
There is a branch of mathematical logic called "[Set theory](https://en.wikipedia.org/wiki/Set_theory)" and that studies sets( OMG 😱, I can't believe!), which can be informally described as unordered collections of distinct element.
Distinct, meaning every element appears only once.
Unorder, in this case, refers to the order not being important.
The elements that make up a set can be any kind of thing: people, letters of the alphabet, numbers, points in space, lines, other geometrical shapes, variables, or even other **sets**.
### Example
![Set example 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gfubvp4o0xtjkdczqc6o.png)
## Properties of set
* Length / Cardinality: number of elements of the set. A set can be empty, finite, or infinite. For example:
![Set example 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6gvw9vt9p5z9ymf56wxd.png)
* Subset/ Superset: a set A is a subset of a set B if all elements of A are also elements of B; B is then a superset of A. For example, all odd numbers set is a subset of all numbers set. All number sets are a superset of odd numbers set. 
![Set example 3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zbgzt5s4msxpc41396bw.png)  

## Operations on sets
* Union: is the set of all elements that are members of both sets.
![union](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l3zivaoea52pyntuemu5.png) 
* Intersection: is the set of all things that are members of both A and B.  
![Intersection](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sl8vjszt9afbc1rky8df.png)
* Complement: is the set of all elements that are members of A, but not members of B.  
![Complement](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sn24wsayizz8pz97gshj.png)

* Symmetric difference: is the set of elements that are part of the sets, but not in their intersection.  
![Symmetric difference](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dqsz079x8p7a6234fkas.png)

# Content
## Sets in JavaScript
### Definition
> 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. [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set)  

### Creating a set
The [constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set#constructor) takes an iterable object, eliminates all duplicated items, and returns an instance of Set.
Don't remember what iterables are ? [check it](https://javascript.info/iterable)

### How JS check if an item is duplicated?  
The operator [===](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality) is used. There are some "edge cases" like +0 is equal to -0? NaN is equal to Nan? that behavior a little different. [Click for more information](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set#value_equality).
Let's check it.
```javascript
const setExample = new Set([1, '1']);
console.log(setExample);
// Set(2) { 1, '1' }
```
Since
```javascript 
console.log(1 === '1');
// false
```
**Be careful since comparing objects, since you are comparing the pointer to the object and not the value**
```javascript
const objA1 = { a: 'a' };
const objA2 = { a: 'a' };
const exampleSet = new Set([objA1, objA2]);
console.log(exampleSet)
// Set(2) { { a: 'a' }, { a: 'a' } }
```
### Set methods / properties
* size : returns the length / cardinality of the set.  
* add(value): append the value to the set, checking if exists. Returns the **same pointer to the original set** with added value.  
* clear(): removes all the elements. Returns undefined.
* delete(value) : removes the element associated to the value. Returns true if the values was deleted else returns false.
* has(value) : returns true is the value exists in the set, else returns false.
```javascript
const exampleSet = new Set([1]);
console.log(exampleSet);
// Set(1) { 1 }
const afterAddMethod = exampleSet.add(2);
// returned pointer to exampleSet. Are you sure? let's check it.
console.log(exampleSet === afterAddMethod);
// true
exampleSet.add(3);
const wasDeleted = exampleSet.delete(1);
console.log(wasDeleted);
// true
console.log(exampleSet);
// Set(2) { 2, 3 }
console.log(exampleSet.has(2));
// true
console.log(exampleSet.has(1));
// false
exampleSet.clear();
console.log(exampleSet);
//Set(0) {}
```
**The follow iteration methods can be used with sets**
* [keys()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/values)  
* [values()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/values)  
* [entries()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/entries)  
* [forEach()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/forEach)  

```javascript
const exampleSet = new Set([1, "2", 3, "4", 4]);
console.log(exampleSet.keys());
// [Set Iterator] { 1, '2', 3, '4', 4 }
console.log(exampleSet.values());
// [Set Iterator] { 1, '2', 3, '4', 4 }
console.log(exampleSet.entries());
/* [Set Entries] {
    [1, 1],
    ['2', '2'],
    [3, 3],
    ['4', '4'],
    [4, 4]
} */
exampleSet.forEach(value => console.log(value));
// 1, 2, 3, 4, 4
```

### MDN Implementation of basic set operations.
After explaining about operation on sets, we check the code implementation.
```javascript
function isSuperset(set, subset) {
    for (let elem of subset) {
        if (!set.has(elem)) {
            return false
        }
    }
    return true
}

function union(setA, setB) {
    let _union = new Set(setA)
    for (let elem of setB) {
        _union.add(elem)
    }
    return _union
}

function intersection(setA, setB) {
    let _intersection = new Set()
    for (let elem of setB) {
        if (setA.has(elem)) {
            _intersection.add(elem)
        }
    }
    return _intersection
}

function symmetricDifference(setA, setB) {
    let _difference = new Set(setA)
    for (let elem of setB) {
        if (_difference.has(elem)) {
            _difference.delete(elem)
        } else {
            _difference.add(elem)
        }
    }
    return _difference
}

function difference(setA, setB) {
    let _difference = new Set(setA)
    for (let elem of setB) {
        _difference.delete(elem)
    }
    return _difference
}  
``` 
**Edit #1:**  
[Alex Lohr](https://dev.to/lexlohr) suggested the following implementations:  
``` javascript
const isSuperset = (set, superset) => [...set].every((item) => superset.has(item))
const union = (set1, set2) => new Set([...set1, ...set2])
const intersection = (set1, set2) => new Set([...set1].filter((item) => set2.has(item)))
const symmetricDifference = (set1, set2) => new Set([...set1, ...set2].filter((item) => set1.has(item) ^ set2.has(item)))
const difference = (set1, set2) => new Set([...set1].filter((item) => !set2.has(item)))
```  

## Examples
```javascript
const setA = new Set([1, 2, 3])
const setB = new Set([3, 4, 5, 6])
console.log(isSuperset(setA, setB))          // returns true
console.log(union(setA, setB))              // returns Set { 1, 2, 3, 4, 5, 6 }
console.log(intersection(setA, setB))       // returns Set { 3 }
console.log(symmetricDifference(setA, setB)) // returns Set { 1, 2, 4, 5, 6 }
console.log(difference(setA, setB))     // returns Set { 1, 2 }
```  
## When can I use Sets?  
### Abstract examples  
*Removing duplicate values of an array.
```javascript
const someArray = [1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 7];
const afterRemovingDuplicatedValues = [...new Set(someArray)];
```
*Given two arrays, return an array with the common values once.
``` javascript
const setA = new Set([31, 141, 245, 22]);
const setB = new Set([1, 22, 12, 33])
console.log(intersection(setA, setB));
```
*Given two arrays, return an array with every value once.
``` javascript
const setA = new Set([31, 141, 245, 22]);
const setB = new Set([1, 22, 12, 33])
console.log(join(setA, setB));
```
### More specifics examples 
*Tags. If everyone can add a tag, I think is a good idea to avoid duplicated tags. Set of tags. 
*Did I see this IP in the last hour? Set of IPs
*Is the user online? Set of users ids.
*Has this URL been banned? Set of URLs.  
# Summary  
**Set is a collection of unique values. It "adds" additional capabilities to arrays and simplifies working on scenarios where the values should be unique.**


I hope I could share with you some knowledge.
Did you learn something new? Let me know in the comments. ❤️
Do you know another use cases? 👆🏽
Did you love it? Share it with your friends. 👏🏽
Don't be afraid to post your thoughts. I'm here to learn from you. 😇
Networking? [LinkedIn](https://www.linkedin.com/in/marcos-mol/) 🤝🏽

Thank you for reading.

Sources:
1) [Wikipedia](https://www.wikipedia.org/)
2) [MDN](https://developer.mozilla.org/en-US/)