# ES6 — Set vs Array — What and when?

Source: https://tpiros.dev/blog/es6-set-vs-array-what-and-when

Let's find out.

## What is Set and what is Array?

**Array** is a structure representing a **block of data** (numbers, objects, etc.) **allocated in consecutive memory**.

Example: `[1,2,3,2]`

### How about Set?

Set, more familiar as a maths concept, is an abstract data type which contains only distinct elements/objects without needing to be ordered by index.

Example: `{1,2,3}`

By definition, Array and Set are technically different concepts.

The biggest difference you'll spot: **elements in Array can be duplicate** (unless you prevent it), and **in Set, they can't** (no matter what you do).

**Array** is considered an "**indexed collection**" type of data structure, while Set is considered a "**keyed collection**".

A quick reminder:

> **Indexed collections** are collections of data ordered by an index value

> **Keyed collections** are collections which use keys; they contain elements which are iterable in the order of insertion.

So if they're different, why compare them?

In practice, given the same data set (no duplicates), you could use either Array or Set to store it. But depending on the use case, **_picking the right structure helps you deliver the optimal solution_**. To make that choice, we need to understand how they're built and what they can do. We've covered "who they are", so let's move on to "how to build one" in JS.

## Constructing

### Array

Array is very direct. To declare a new array in JS, you can use the literal syntax:

```javascript
var arr = []; //Empty array
var arr = [1, 2, 3]; //Array which contains 1,2,3
```

Or use the built-in constructor:

```javascript
var arr = new Array(); //empty array
var arr = new Array(1, 2, 3); //Array which contains 1,2,3
```

Or even cooler:

```javascript
var arr = new Array(); //empty array
var arr = new Array(1, 2, 3); //Array which contains 1,2,3
```

**_Side notes_**:

One piece of advice: don't use `new Array()` unless you _really really really_ need to, because:

- It performs much slower than the normal `[]` literal. (A topic for another article, maybe.)
- `[]` saves more typing time (try it)
- You can end up making classic mistakes such as:

```javascript
var arr1 = new Array(10); //arr1[0] = undefined but arr1.length = 10
var arr2 = [10]; // arr2[0] = 10 and arr2.length = 1;
var arr3 = new Array(1, 2, 3); //[1,2,3]
var arr4 = [1, 2, 3]; //[1,2,3]
```

So rule number one: keep it simple.

## Set

Set has a built-in constructor. There's no shortcut like with Array.

> Set([iterable])

To create a new set, use the **_new_** syntax:

```javascript
var emptySet = new Set();
var exampleSet = new Set([1, 2, 3]);
```

But definitely not: `new Set(1);`

Set receives an **iterable** object as its input parameter and creates the set from it. You can construct a set from an array, but _it'll only include distinct elements from that array_. No duplicates.

And you can convert a set back to an array using `Array.from()`:

```javascript
var set = new Set([1, 2, 3]); // {1,2,3}
var arr = Array.from(set); //[1,2,3]
```

Right, now that we know how to create them, what about their capabilities?

Let's do a small comparison between the most basic methods Array/Set provides:

## Locating an element / Accessing an element

- Set doesn't support random access to an element by index like Array does:

```javascript
console.log(set[0]); //undefined
console.log(arr[0]); //1
```

- Because Array data is stored in consecutive memory, the CPU can fetch it much faster due to pre-fetching.
- So in general, **_accessing elements in Array (one after another, as in a for loop) is quicker and more efficient_** compared to other abstract data types.
- Checking if an element exists in Set has simpler syntax than Array: `Set.prototype.has(value)` vs `Array.prototype.indexOf(value)`

```javascript
console.log(set.has(0)); // boolean - false
console.log(arr.indexOf(0)); // -1
console.log(set.has(1)); //true
console.log(arr.indexOf(1)); //0
```

With Array, you need an extra check if you want a boolean:

```javascript
var isExist = arr.indexOf(1) !== -1;
```

> Note: ES6 does provide `Array.prototype.includes()` which behaves similarly to `has()`, but it isn't supported widely (not in IE, surprise).

## Add/Insert new element

- Adding a new element to Array can be done in O(1) using `Array.prototype.push()`, which appends to the end.

```javascript
arr.push(4); //[1,2,3,4]
```

- Or in `O(n)` using `Array.prototype.unshift()`, which prepends to the beginning (where `n` is the length of the current array).

```javascript
arr.unshift(3); //[3,1,2,3]
arr.unshift(5, 6); //[5,6,3,1,2,3]
```

- In Set, there's only one way to add a new element: `Set.prototype.add()`. Because Set must maintain the "**distinct**" property, each call to `add()` needs to check all members for duplicates. In general `add()` takes `O(n)` running time. But thanks to **hash table implementation**, `add()` in Set will likely take only `O(1)`.

```javascript
set.add(3); //{1,2,3}
set.add(4); //{1,2,3,4}
```

So Set performs roughly the same as Array when adding elements. What about removing?

## Remove element

- **Array** gives you several methods to remove an element:
  `Pop()` removes and returns the last element. This takes `O(1)`.

```javascript
arr.pop(); //return 4, [5,6,1,2,3]
```

`Shift()` removes and returns the first element. This takes `O(n)`.

```javascript
arr.shift(); //return 5; [6,1,2,3]
```

`Splice(index, deleteCount)` removes `deleteCount` elements starting from `index`. This can take up to `O(n)`.

```javascript
arr.splice(0, 1); //[1,2,3]
```

- In Set, we use:

`Delete(element)` removes a specific given `element` from Set.

```javascript
set.delete(4); //{1,2,3}
```

`Clear()` removes all elements from Set.

```javascript
set.clear(); //{}
```

- While **Array doesn't have a native method** to remove a specific element by value (unless you know its index), Set has `delete()`. Simple and clean.

Array does provide many more native methods (`reduce()`, `reverse()`, `sort()`, etc.) compared to Set, which currently only has the basics mentioned above. So why would you ever prefer Set?

## So, when is Set better? And when is Array better?

- Set isn't meant to replace Array entirely. It provides additional support for what Array is missing.
- Since Set only contains distinct elements, it makes life much easier when you know in advance you want to avoid duplicates.
- Basic set operations like `union()`, `intersect()`, `difference()` are easily implemented using the native built-in methods. The `delete()` method makes intersect/union between 2 Sets much more comfortable than doing the same with 2 Arrays.
- Array is the right choice when you need elements ordered for quick access, when you're doing heavy modification (removing and adding elements), or when you need direct index access (try doing Binary Search on a Set instead of an Array: how would you access the middle element?).

# Conclusion

In general, Set doesn't have a huge clear advantage over Array, except in specific cases: when you want to maintain distinct data with minimal effort, or when you're working with multiple distinct data sets using basic set operations and don't need direct element access.

Otherwise, Array should always be the choice. The CPU has an easier time fetching the element when it's needed.

Do you agree? Feel free to discuss.

> Disclaimer: This post is originally posted in [FrontEnd Weekly](https://medium.com/front-end-weekly/es6-set-vs-array-what-and-when-efc055655e1a)

If you'd like to catch up with me sometimes, follow me on [Twitter](https://twitter.com/MayaShavin) | [Facebook](https://www.facebook.com/mayashavin/) or simply visit my [portfolio website](https://mayashavin.com/).
