Working with Sets Flashcards
What is a Set
?
Set
objects are collections of values. A value in the set may only occur once; it is unique in the set’s collection. You can iterate through the elements of a set in insertion order. The insertion order corresponds to the order in which each element was inserted into the set by the add()
method successfully (that is, there wasn’t an identical element already in the set when add()
was called).
“Set - JavaScript | MDN” (MDN Web Docs). Retrieved June 6, 2024.
What did we use before Set
s?
Before ES6, JavaScript didn’t have a data structure for sets. Instead, two workarounds were used:
- The keys of an object were used as a set of strings.
- Arrays were used as sets of arbitrary values. The downside is that checking membership (if an Array contains a value) is slower.
Since ES6, JavaScript has the data structure Set
, which can contain arbitrary values and performs membership checks quickly.
“Sets (Set
) * JavaScript for impatient programmers (ES2022 edition)” (exploringjs.com). Retrieved June 6, 2024.
How do you create a Set
?
There are three common ways of creating Set
s.
First, you can use the constructor without any parameters to create an empty Set
:
const emptySet = new Set(); assert.equal(emptySet.size, 0);
Second, you can pass an iterable (e.g., an Array
) to the constructor. The iterated values become elements of the new Set
:
const set = new Set(['red', 'green', 'blue']);
Third, the .add()
method adds elements to a Set
and is chainable:
const set = new Set() .add('red') .add('green') .add('blue');
“Creating Sets” (exploringjs.com). Retrieved June 6, 2024.
How can you add, remove, and check membership in a Set
?
.add()
adds an element to a Set
.
const set = new Set(); set.add('red');
.has()
checks if an element is a member of a Set
.
assert.equal(set.has('red'), true);
.delete()
removes an element from a Set
.
assert.equal(set.delete('red'), true); // there was a deletion assert.equal(set.has('red'), false);
“Adding, removing, checking membership” (exploringjs.com). Retrieved June 7, 2024.
How can you determine the size of a Set
?
.size
contains the number of elements in a Set
.
const set = new Set() .add('foo') .add('bar'); assert.equal(set.size, 2)
“Determining the size of a Set and clearing it” (exploringjs.com). Retrieved June 7, 2024.
How can you clear a Set
?
.clear()
removes all elements of a Set.
set.clear(); assert.equal(set.size, 0)
“Determining the size of a Set and clearing it” (exploringjs.com). Retrieved June 7, 2024.
How can you iterate over Set
s?
Set
s are iterable and the for-of
loop works as you’d expect:
const set = new Set(['red', 'green', 'blue']); for (const x of set) { console.log(x); } // Output: // 'red' // 'green' // 'blue'
As you can see, Set
s preserve insertion order. That is, elements are always iterated over in the order in which they were added.
Given that Set
s are iterable, you can use Array.from()
to convert them to Arrays:
const set = new Set(['red', 'green', 'blue']); const arr = Array.from(set); // ['red', 'green', 'blue']
“Iterating over Sets” (exploringjs.com). Retrieved June 7, 2024.
How can you remove duplicates on an Array
using Set
s?
Converting an Array
to a Set
and back, removes duplicates from the Array:
assert.deepEqual( Array.from(new Set([1, 2, 1, 2, 3, 3, 3])), [1, 2, 3]);
“Removing duplicates from an Array” (exploringjs.com). Retrieved June 7, 2024.
What Set
elements are considered equal?
As with Map
keys, Set
elements are compared similarly to ===,
with the exception of NaN
being equal to itself.
const set = new Set([NaN, NaN, NaN]); set.size; // 1 set.has(NaN); // true
As with ===,
two different objects are never considered equal (and there is no way to change that at the moment):
const set = new Set(); set.add({}); set.size; // 1 set.add({}); set.size; // 2
“What Set
elements are considered equal?” (exploringjs.com). Retrieved June 12, 2024.
How can you compute the union of two Set
s (a ∪ b)?
Computing the union of two Sets a
and b
means creating a Set
that contains the elements of both a
and b
.
const a = new Set([1,2,3]); const b = new Set([4,3,2]); // Use spreading to concatenate two iterables const union = new Set([...a, ...b]); assert.deepEqual(Array.from(union), [1, 2, 3, 4]);
“Set
Union (a ∪ b)” (exploringjs.com). Retrieved June 12, 2024.
How can you compute the intersection of two Set
s (a ∩ b) ?
Computing the intersection of two Set
s a
and b
means creating a Set
that contains those elements of a
that are also in b
.
const a = new Set([1,2,3]); const b = new Set([4,3,2]); const intersection = new Set( Array.from(a).filter(x => b.has(x)) ); assert.deepEqual( Array.from(intersection), [2, 3] );
“Set
Intersection (a ∩ b)” (exploringjs.com). Retrieved June 12, 2024.
How can you compute the difference of two Set
s (a \ b)?
Computing the difference between two Set
s a
and b
means creating a Set
that contains those elements of a
that are not in b
. This operation is also sometimes called minus (−
).
const a = new Set([1,2,3]); const b = new Set([4,3,2]); const difference = new Set( Array.from(a).filter(x => !b.has(x)) ); assert.deepEqual( Array.from(difference), [1] );
“Set
Difference (a \ b)” (exploringjs.com). Retrieved June 12, 2024.
How can you map over a Set
?
Sets don’t have a method .map()
. But we can borrow the one that Arrays have:
const set = new Set([1, 2, 3]); const mappedSet = new Set( Array.from(set).map(x => x * 2) ); // Convert mappedSet to an Array to check what’s inside it assert.deepEqual( Array.from(mappedSet), [2, 4, 6] );
“Mapping over Sets” (exploringjs.com). Retrieved June 12, 2024.
How can you filter over a Set
?
We can’t directly .filter()
Set
s, so we need to use the corresponding Array
method:
const set = new Set([1, 2, 3, 4, 5]); const filteredSet = new Set( Array.from(set).filter(x => (x % 2) === 0) ); assert.deepEqual( Array.from(filteredSet), [2, 4] );
“Filtering Sets” (exploringjs.com). Retrieved July 1, 2024.
Why do Set
s have a .size
, while Array
s have a .length
?
In JavaScript, indexable sequences (such as Array
s and string
s) have a .length
, while unindexed collections (such as Maps
and Sets
) have a .size
:
-
.length
is based on indices; it is always the highest index plus one. -
.size
counts the number of elements in a collection.
“Why do Maps have a .size, while Arrays have a .length?” (exploringjs.com). Retrieved July 1, 2024.