In this blogpost, we will see multiple ways of finding length of Set. Let’s begin this journey into one of JavaScript’s unique and powerful data structures!
Refresher: Sets in JavaScript:
- A Set is a collection of unique values. Unlike arrays, each value in a Set must be unique. JavaScript Sets are part of the ES6 (ECMAScript 2015) standard.
- Some important APIs of Javascript Set are below:
// Creating Set:
let mySet = new Set();
console.log(mySet); // Output: Set(0) {}
// Adding elemets to Set:
mySet.add('apple');
mySet.add('banana');
console.log(mySet); // Output: Set(2) {"apple", "banana"}
// Removing Set elements:
mySet.delete('apple');
console.log(mySet); // Output: Set(1) {"banana"}
// Checking existence of an element with .has()
console.log(mySet.has('banana')); // Output: true
console.log(mySet.has('grape')); // Output: false
// Clearing Set with .clear()
mySet.clear();
console.log(mySet); // Output: Set(0) {}
Ways to find Set size in JavaScript
Using the size property to find Set size in JavaScript
The size
property of a Set object returns the number of elements in the Set. It gets automatically updated whenever size of Set changes. In below example, see the size of set changing after each action on set.
// Creating Empty Set (size is 0)
let mySet = new Set();
console.log(mySet.size()); // Output: 0
// Adding 2 elements to Set (size is 2 now)
mySet.add('apple');
mySet.add('banana');
console.log(mySet.size); // Output: 2
// Removing 1 element of Set (size is 1 now)
mySet.delete('banana');
console.log(mySet.size); // Output: 1
// Clearing the set: (seize becomes 0)
mySet.clear();
console.log(mySet.size); // Output: 0
Using counter in a loop, like in Set.forEach()
Not really a direct method to get the length, but you can iterate over a Set and count elements.
let count = 0;
mySet.forEach(() => count++);
console.log(count); // Output: 1
Tips on Set and its Size
Some tips on set, specially regarding sizing a set.
Set’s size vs. Array’s length
Arrays in JavaScript have a length
property that indicates the number of elements in the array. However, unlike the size
property of a Set, Array.length
can be modified, which can lead to some interesting behaviors. Essentially it extends the array. Basically, modifying Array’s length
can either shrink or expand your array (with empty elements). Lets see this.
const arr = ['a', 'b', 'c'];
console.log(arr.length); // Output: 3
// Manually changing the length property
arr.length = 10;
console.log(arr.length); // Output: 10
console.log(arr); // Output: ['a', 'b', 'c', <7 empty slots>]
- Initially, the array
arr
contains three elements, soarr.length
returns 3. - We then manually set
arr.length
to 10. This doesn’t add new elements to the array but extends the array with empty slots. - The array now technically has a length of 10, but seven of those positions are empty.
But Set’s size
is read-only, you cant modify it using this property.
let mySet = new Set([1, 2, 3]);
console.log(mySet.size); // Output: 3
// Attempting to change the size property has no effect
mySet.size = 10;
// Size still remains 3
console.log(mySet.size); // Output: 3
Sparse Arrays exist, not Sparse Sets
JavaScript arrays can be sparse, meaning they can have empty slots. Sets, however, will always contain only the elements that are explicitly added (and may be undefined
too, if you didnt’t pass anything explicitly in add()
). So Set will never be Sparse like Arrays.
const sparseArray = [1, , , 4]; // An array with empty slots
console.log(sparseArray.length); // Output: 4
// Set with numbers 1,4 and 2 undefined = total 3 unique elements
const nonSparseSet = new Set().add(1).add().add().add(4);
console.log(nonSparseSet.size);
// Output: 3 (1 for the two undefined, and then 1 & 4).
- In Arrays: The length counts all slots, including the empty ones.
- In Set:
- the first
add(1)
adds the number1
tomySet
. - The subsequent
add()
calls addundefined
to the Set. Sinceundefined
is treated as a unique element and it wasn’t in the Set before, the Set’s size increases by one only (not two). - Then after adding 4, the final size of
mySet
is 3, comprising1
, 4 andundefined
.
- the first
Handling Non-Primitive Types:
Sets use the “SameValueZero” algorithm for equality comparison. This means that while primitive values are compared by their actual values, non-primitive values (like objects and arrays) are compared by reference.
So when non-primitive types are added to a Set, the comparison is based on their memory reference, not the structural or content similarity. In following examples even if we add two empty objects or arrays, despite their contents being similar, they are different references (and hence different objects).
let set = new Set();
// Adding 2 empty objects (but still they are two different References)
set.add({});
set.add({});
// Adding 2 empty arrays (but still they are two different References)
set.add([]);
set.add([]);
console.log(set.size); // Output: 4 (different object references for all 4)
Implications:
- Uniqueness in Sets: If you add multiple objects or arrays with identical contents to a Set, they will be treated as separate entities. This is important to remember when working with Sets to store collections of objects or arrays.
- Mutability of Set Elements: Elements in a Set, even if they are objects or arrays, are mutable. Changing the properties of an object within a Set doesn’t affect the Set’s size or the presence of the object. See below section on this.
- Use Cases for Sets with Non-Primitive Types: For maintaining a collection of unique objects or arrays, Sets are ideal where the identity of each item (its reference) is important. But not ideal if uniqueness on the content or objects structure is required.
Size unchanged on mutating Set elements:
Can mutating elements within a Set affects its size? Yes, but only in case of reference type elements. In case of primitive elements, the question of mutating primitive values doesn’t really make sense. Lets see in detail
Sets and Primitive Types
Primitive types (like strings, numbers, booleans) in a Set are immutable by nature. That means when you add a primitive value to a Set, you can’t change the value itself. Any ‘modification’ is actually the addition of a new value or removal of the old one. You can’t really replace a primitive value by something else.
So whatever is the size of the set at that moment (as per addition or removal and number of unique elements), will be shown.
let mySet = new Set([1, 2, 3]);
mySet.add(2); // Attempting to add an existing primitive value
console.log(mySet.size); // Output: 3
mySet.delete(2); // Removing the value '2'
mySet.add(20); // Adding a new value
console.log(mySet.size); // Output: 3
Sets and Reference Types (Size unchanged on mutation)
For reference types (like objects, arrays), Sets store the reference (memory address) to the object, not the object itself. Mutating the object’s properties doesn’t change the memory address, hence the Set size remains unchanged.
So whatever is the size of the set at that moment (as per addition or removal and number of unique elements), will be shown.
let mySet = new Set();
let obj = { key: 'value' };
mySet.add(obj);
console.log(mySet.size); // Output: 1
// Mutating the object
obj.key = 'new value';
console.log(mySet.size); // Output: 1
console.log([...mySet]); // Output: [{ key: 'new value' }]
- Adding an object
obj
tomySet
increases its size to 1. - Even after modifying the
obj
‘s property, the Set size remains 1 because the reference toobj
hasn’t changed; only the content it points to has been modified.
🧪Practice Coding Problem: Set Length Detective 🕵️♂️
In the spirit of Test Driven Development ( 😁), lets test our understanding by solving a problem.
Write a function that accepts a Set and returns its size. The twist? You can’t use the
size
property!Problem (JavaScript)/** * Calculates the length of a given Set without using the 'size' property. * @param {Set} set - The Set to measure. * @return {number} - The length of the Set. */ function setLengthDetector(set) { // Implementation } let testSet = new Set(['a', 'b', 'c']); console.log(setLengthDetector(testSet)); // Expected Output: 3
Please attempt before seeing the Answer:
function setLengthDetector(set) {
let length = 0;
set.forEach(() => length++);
return length;
}
Explanation:
- This function iterates over the Set using
forEach
and increments a counter for each element. - So it calculates the Set’s length without relying on the
size
property.
I hope you are expert in sizing Sets now. 🤓 While arrays might stretch/slice the truth with their lengths, Sets always keep it real with their sizes.
Keep it real, and keep coding! 🚀👨💻