Book of Coding


Maps and Sets in JavaScript

1. Use maps

In programming, maps are a type of data structure in which key-value pairs can be stored. This means that individual values can be stored for keys within a map, which can then be retrieved via the keys. The keys within a map must be unique, but values can occur more than once.

Maps are represented by the type Map, so instances can be created using the corresponding constructor function. An array of arrays is passed as a parameter. The arrays each contain the key as the first element and the value as the second element.

Complete Code - Examples/Part_196/main.js...

 const cityPopulation = new Map(         // Create a map ...
   [                                     // ... on the basis of an array
     ['Tokyo', 37000000],
     ['Delhi', 32000000],
     ['Cairo', 22000000],
     ['New York', 8000000],
     ['Berlin', 4000000]
   ]
 );
 console.log(cityPopulation.size);       // output: 5
				    

KeyValue
Tokyo 37.000.000
Delhi 32.000.000
Cairo 22.000.000
New York 8.000.000
Berlin 4.000.000

The constructor function of Map does not necessarily expect an array, but an object that can be iterated. An iterable object is an object that defines its own iteration behaviour so that it can be used directly as input in a loop, for example.


1.1. Basic operations

Here is a list of the methods that are possible with maps:

MethodExplanation
clear() Deletes all key-value pairs from the map.
delete() Deletes the value of a transferred key from the map. If the deletion is successful, the method returns true, otherwise false.
get() Returns the associated value for a key. If the key does not exist in the map, the method returns an undefined.
has() Checks whether there is a value for a key in the map. If yes, the method returns true, otherwise false.
set() Sets the corresponding value for a key. If the key already exists in the map, the value associated with it is overwritten.
size Contains the number of key-value pairs in the map.
entries() Returns an iterator that can be used to iterate over the key-value pairs of the map
keys() Analogue to entries(), this method returns an iterator for the keys of the map.
values() Analogue to entries(), the method returns an iterator for the values of the map.

The use of Map:

Complete Code - Examples/Part_197/main.js...

 const cityPopulation = new Map();               // Create the map
 cityPopulation.set('Tokyo', 37000000);          // Add multiple entries
 cityPopulation.set('Delhi', 32000000);
 cityPopulation.set('Cairo', 22000000);
 cityPopulation.set('New York', 8000000);
 cityPopulation.set('Berlin', 4000000);
 console.log(cityPopulation.get('Tokyo'));       // output: 37000000
 console.log(cityPopulation.size);               // output: 5
 console.log(cityPopulation.has('Tokyo'));       // output: true
 cityPopulation.delete('Tokyo');                 // Delete an entry
 console.log(cityPopulation.has('Tokyo'));       // output: false
 console.log(
     cityPopulation.has('Shanghai')              // output: false
 );
 cityPopulation.clear();                         // Delete all entries
 console.log(cityPopulation.size);               // output: 0
                        

The method calls of set() can be conveniently chained, as the method always returns the map as a return value and you can therefore call set() again directly:

Complete Code - Examples/Part_198/main.js...

 const cityPopulation = new Map()        // Create a map ...
   .set('Tokyo', 37000000)               // ... with method chaining
   .set('Delhi', 32000000)
   .set('Cairo', 22000000)
   .set('New York', 8000000)
   .set('Berlin', 4000000);
 console.log(cityPopulation.size);       // output: 5
                        

1.2. Iterate over maps

The methods keys(), values() and entries() return so-called iterators, which can be used to iterate over the individual entries of the map:


Iterate over the keys of a map
Complete Code - Examples/Part_199/main.js...

 const cityPopulation = new Map(         // Create a map ...
   [                                     // ... on the basis of an array
     ['Tokyo', 37000000],
     ['Delhi', 32000000],
     ['Cairo', 22000000],
     ['New York', 8000000],
     ['Berlin', 4000000]
   ]
 );
 for (const city of cityPopulation.keys()) {
   console.log(city);
 }
                            

Here, the keys() method and the for-of loop are used to iterate over the keys of the cityPopulation map. The programme then returns the output Tokyo, Delhi, Cairo, New York, Berlin.


for-of vs for-in loop

The for-of loop differs from the for-in loop in that it does not iterate over the names of the object properties, but over the values associated with these properties.

Complete Code - Examples/Part_200/main.js...

 const numbers = [ 7, 10, 18, 26, 42 ];
 numbers.name = "Array of numbers";
 // for-in-Loop
 for (let i in numbers) {
   console.log(i);   // 0, 1, 2, 3, 4, name
 }
 // for-of-Loop
 for (let i of numbers) {
   console.log(i);   // 7, 10, 18, 26, 42
 }
                            

The for-in loop outputs indices, which represent the properties for arrays, as well as the manually added name property, whereas the for-of loop outputs the values stored in the array.


Iterate over the values of a map

Here, the values() method is used to iterate over the values contained in the map:

Complete Code - Examples/Part_201/main.js...

 const cityPopulation = new Map();           // Create the map
 cityPopulation.set('Tokyo', 37000000);      // Add multiple entries
 cityPopulation.set('Delhi', 32000000);
 cityPopulation.set('Cairo', 22000000);
 cityPopulation.set('New York', 8000000);
 cityPopulation.set('Berlin', 4000000);
 for (let population of cityPopulation.values()) {
   console.log(population);
 }

 /* output:
 37000000
 32000000
 22000000
 8000000
 4000000
 */
                            

Iterate over the key-value pairs of a map

If you want to iterate over the keys and values, use the entries() method. The corresponding iterator returned by this method returns an array with two entries in each iteration: the key in the first position and the stored value in the second position.

Complete Code - Examples/Part_202/main.js...

 const cityPopulation = new Map();               // Create the map
 cityPopulation.set('Tokyo', 37000000);          // Add multiple entries
 cityPopulation.set('Delhi', 32000000);
 cityPopulation.set('Cairo', 22000000);
 cityPopulation.set('New York', 8000000);
 cityPopulation.set('Berlin', 4000000);

 for (let entry of cityPopulation.entries()) {
   console.log(entry[0]);                        // Key
   console.log(entry[1]);                        // Value
 }

 // Alternatively, access via array destructuring:
 for (let [ city, population ] of cityPopulation.entries()) {
   console.log(city);
   console.log(population);
 }

 /* output:
 Tokyo
 37000000
 Delhi
 32000000
 Cairo
 22000000
 New York
 8000000
 Berlin
 4000000
 ...
 */
                            

Since the iterator returned by entries() is also the iterator that is stored in the Map object by default, you can also use the map directly as input for the for-of loop in this case:

Complete Code - Examples/Part_203/main.js...

 const cityPopulation = new Map();           // Create the map
 cityPopulation.set('Tokyo', 37000000);      // Add multiple entries
 cityPopulation.set('Delhi', 32000000);
 cityPopulation.set('Cairo', 22000000);
 cityPopulation.set('New York', 8000000);
 cityPopulation.set('Berlin', 4000000);

 for (let entry of cityPopulation) {
   console.log(entry[0]);                    // Key
   console.log(entry[1]);                    // Value
 }

 // Alternatively, access via array destructuring:
 for (let [ city, population ] of cityPopulation) {
   console.log(city);
   console.log(population);
 }

 /* output:
 Tokyo
 37000000
 Delhi
 32000000
 Cairo
 22000000
 New York
 8000000
 Berlin
 4000000
 ...
 */
                            

1.3. Use Weak Maps

In addition to the Map data type, the ECMAScript standard also provides the WeakMap data type. Weak maps are similar to normal maps, but they differ in one important respect: objects that are used as keys can be deleted as part of the garbage collection if these objects are no longer referenced. The objects in a weak map are therefore weakly referenced.


Garbage collection

In software development, this term refers to a mechanism that ensures that memory areas that are no longer required are regularly released during the runtime of a program in order to minimise the memory requirements of the program.


Weak maps have a direct impact on the API: Firstly, only objects can be used as keys and not primitive data types, as is the case with normal maps. This means that character strings are not permitted as keys in a weak map.

Secondly, the methods keys(), values() and entries() are not available for weak maps, as these methods would return iterators for which there is no guarantee that the internal state is still correct after a garbage collection. The size property is not available for a similar reason.

An example of the use of Weak Maps:

Complete Code - Examples/Part_204/main.js...

 const city1 = {
   name: 'Tokyo'
 };
 const city2 = {
   name: 'Delhi'
 };
 const city3 = {
   name: 'Cairo'
 };
 const city4 = {
   name: 'New York'
 };
 const city5 = {
   name: 'Berlin'
 };
 const city6 = {
   name: 'Paris'
 };
 const cityPopulation = new WeakMap();           // Create the map
 cityPopulation.set(city1, 37000000);            // Add multiple entries
 cityPopulation.set(city2, 32000000);
 cityPopulation.set(city3, 22000000);
 cityPopulation.set(city4, 8000000);
 cityPopulation.set(city5, 4000000);
 console.log(cityPopulation.get(city1));         // output: 37000000
 console.log(cityPopulation.has(city1));         // output: true
 cityPopulation.delete(city1);                   // Delete an entry
 console.log(cityPopulation.has(city1));         // output: false
 console.log(
     cityPopulation.has(city6)                   // output: false
 );
 console.log(cityPopulation);
                        

The keys used here are no longer strings but objects.


2. Use sets

In programming, a set is a data structure that is similar to a list, but in which the values may only occur once, i.e. duplicate values are not permitted. Sets have been available since ES2015 and are represented by the Set object. Whether two values are the same is checked for strict equality, i.e. both the value and type of a variable are taken into account.

The constructor function Set is used to create a set. As with maps, an array containing the initial values to be added to the set can be passed as the value:

Complete Code - Examples/Part_205/main.js...

 const cities = new Set(         // Create a set ...
   [                             // ... on the basis of an array
     'Tokyo',
     'Tokyo',
     'Delhi',
     'Cairo',
     'New York',
     'Berlin'
   ]
 );
 console.log(cities.size);      // output: 5
				    

A set was created here that contains five character strings as values. The duplicate character string Tokyo is only added to the set once, so that the set then has the size 5.


2.1. Basic operations

Here is a list of the methods that are possible with sets:

MethodExplanation
add() Adds an element to the set.
clear() Deletes all elements from the set.
delete() Deletes the transferred element from the set.
has() Checks whether the transferred element is contained in the set.
entries() Returns an iterator containing the value-value pairs of the set. The order of the pairs corresponds to the order in which they were added to the set.
keys() Returns an iterator containing the values of the set. The order of the values corresponds to the order in which they were added to the set.
values() Like keys(), returns an iterator containing the values of the set. The order of the values corresponds to the order in which they were added to the set.
size Property that represents the number of elements in the set.

The use of Set:

Complete Code - Examples/Part_206/main.js...

 const cities = new Set();              // Create the set
 cities.add('Tokyo');                   // Add different values
 cities.add('Tokyo');
 cities.add('Delhi');
 cities.add('Cairo');
 cities.add('New York');
 cities.add('Berlin');
 console.log(cities.size);              // output: 5
 console.log(cities.has('Tokyo'));      // output: true
 cities.delete('Tokyo');                // Delete a value
 console.log(cities.has('Tokyo'));      // output: false
 console.log(
   cities.has('Paris')                  // output: false
 );
 cities.clear();                        // Delete all values  
 console.log(cities.size);              // output: 0
                        

It is also possible to chain the calls of the sset() method:

Complete Code - Examples/Part_207/main.js...

 const cities = new Set()               // Create the set
   .add('Tokyo')                        // ... with concatenation
   .add('Delhi')
   .add('Cairo')
   .add('New York')
   .add('Berlin');
 console.log(cities.size);              // output: 5
                        

2.2. Iterate over sets

To iterate over the entries in a set, the methods keys(), values() and entries() are available, as with maps, which can be used to return individual iterators. As sets do not contain keys, the keys() and values() methods return an iterator for the values in the respective set and the entries() method returns an iterator that returns an array with two entries in each iteration, both of which represent the respective value.

Complete Code - Examples/Part_208/main.js...

 const cities = new Set(         
   [                             
     'Tokyo',
     'Delhi',
     'Cairo',
     'New York',
     'Berlin'
   ]
 );

 for (let city of cities.keys()) {
   console.log(city);
 }
 // output: "Tokyo", "Delhi", "Cairo", "New York", "Berlin"

 for (let city of cities.values()) {
   console.log(city);
 }
 // output: "Tokyo", "Delhi", "Cairo", "New York", "Berlin

 for (let city of cities.entries()) {
   console.log(city[0]); // Value, e.g. "Tokyo"
   console.log(city[1]); // Value, e.g. "Tokyo"
 }

 for (let city of cities) {
   console.log(city);
 }
 // output: "Tokyo", "Delhi", "Cairo", "New York", "Berlin"
                        

2.3. Use Weak Sets

For sets, there is the Weak-Sets alternative, which is represented by the type WeakSet. Here, the objects that are no longer referenced elsewhere are regularly deleted from the set (garbage collection). Weak sets do not provide the keys(), values() and entries() methods, have no size property and no clear() method. And here too, as with weak maps, no prmtive data types can be added as values of a weak set.

Complete Code - Examples/Part_209/main.js...

 const city1 = {
     name: 'Tokyo'
   };
   const city2 = {
     name: 'Delhi'
   };
   const city3 = {
     name: 'Cairo'
   };
   const city4 = {
     name: 'New York'
   };
   const city5 = {
     name: 'Berlin'
   };
   const city6 = {
     name: 'Paris'
   };
 const cities = new WeakSet(
   [
     city1,
     city2,
     city3,
     city4,
     city5
   ]
 );
 console.log(cities.has(city1));     // output: true
 cities.delete(city1);               // Delete a value
 console.log(cities.has(city1));     // output: false
 console.log(
   cities.has(city6)                  // output: false
 );
 console.log(cities);
                        

Related links: