Sets

Pairing Keys with Values

Introduction

Sets are another collection option that we have available to us in JS. Sets work very similar to Arrays. The difference between the two is that values in a Set must be unique.

Example

const myArray = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4] // This is just fine

But if we create a Set from this array...

const myArray = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4] // This is just fine
const mySet = new Set(myArray) // mySet = [1, 2, 3, 4]

Since a Set will only hold unique values, we only get one instance of each number.


Working with Sets

Sets are great for collections you need to keep unique values in. For example, all of the keys in a Map need to be unique. So if you get a collection of keys from a Map, what you're getting back is a Set.

Let's take a look at making a new Set with a playing card example:

const suits = new Set(['♤', '♡', '♧', '♢']) // Spades, Hearts, Clubs, Diamonds
const vals = new Set(['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A'])

const deck = new Set()

for (let suit of suits) {
  for (let val of vals) {
    deck.add(`${val}${suit}`)
  }
}

This gives us a full deck of cards! What's nice about using a Set here is that we can be sure that every value we get is unique. Which, after all, is what you need for a reliable deck of cards.

We can now make some assertions on this set and know we're dealing with unique values. Let's make sure this deck has the Ace of Spades:

deck.has('A♤') // returns true

Removing Values

Let's say we want to deal a 5 card poker hand. Picking 5 random cards isn't too difficult a task, but the trick is that we want to make sure we can't deal the same card twice. How can we pull that off?

const suits = new Set(['♤', '♡', '♧', '♢']) // Spades, Hearts, Clubs, Diamonds
const vals = new Set(['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A'])

const deck = new Set()

for (let suit of suits) {
  for (let val of vals) {
    deck.add(`${val}${suit}`)
  }
}

const hand = new Set()

for (let i = 0; i < 5; i++) {
  const randomIndex = Math.floor(Math.random() * deck.size)
  const card = [...deck][randomIndex]
  hand.add(card)
  deck.delete(card)
}

console.log(hand)

Try running that code in your browsers console. It works!

Let's step through what we're doing here though. First, we're setting up a loop that will run 5 times. For each iteration we're choosing a random index in our Set and using it to pick a random value in our Set and assigning it to card.

What is [...deck][randomIndex] doing?

Good question. [...deck] is making an Array out of our Set so that we can select a value by an index. Adding [randomIndex] to the end actual selects the value at the index we generate.

Then, we're adding the selected card to our hand Set.

Finally, we're removing that card from our deck Set.


Other Set Methods

Method Result
clear() Removes all values from the Set
entries() Returns an iterator with key/value pairs of indices and the actual Set values
forEach() Accepts a callback that will run for every value in the Set
has(value) Returns a Boolean value reflecting whether the Set contains the value

Conclusion

Sets are a really useful collection due to their ability to store unique values. Familiarize yourself and try to use Sets over Arrays whenever possible.