Maps

Pairing Keys with Values

What is it?

A map is a construct that allows us to pair keys and values. Maps are sometimes referred to as tables or dictionaries.

Let's say that I have the following student information:

Student ID Name
23A52 Harvey Dent
68Z29 Jessica Jones
57W85 J Jonah Jameson

Each student will have a unique ID, but multiple students could have the same name.


How do I build it?

Each student ID (key) corresponds to a student name (value). Each of these key/value pairs is known as a map entry. In Java, we can create a Map to hold these entries.

key
↓↓↓

Student ID
value
↓↓↓

Name
23A52 Harvey Dent
68Z29 Jessica Jones
57W85 J Jonah Jameson

Map is a parameterized type, so we declare it thus:

const students = new Map();

To add students, we use set(key, value):

students.set("23A52", "Harvey Dent")
students.set("68Z29", "Jessica Jones")
students.set("57W85", "J Jonah Jameson")

Let's look at what we've got:

console.log(`The students are ${students}`); // prints "The students are [object Map]"

[object Map] is the default response from the toString() method. The good news is that we do have a Map. We'll take a look at how to get a more informative response from toString later.


What is it Good For?

We know that we could use an array or an object to hold collections of things, so why Map?

Imagine we wanted to look up students by name from our example student information.

First, we'd need to create an object to hold student ID and name:

class Student {
  constructor(id, name) {
    this.id = id
    this.name = name
  }
}

Assuming we have populated a collection of Student objects, to find a student by ID, we'd do something like this:

for(let current of students) {
  if("23A52" === current.id)) {
    console.log("Found the student!");
    console.log("The student's name name is " + current.name);
    break;
  }
}

Maps make this easier. Also, what if there were 20,000 students and the one we were looking for was 19,998th in our list? Maps also perform better for doing lookups like this.


Finding our Student

Map defines a method called get. Given a key, the get method will return its value.

Assuming we have populated a Map named students whose keys are IDs (Strings) and whose values are student names (Strings), finding a student by ID with a Map is simple:

const studentName = students.get("23A52");
console.log("Found the student!");
console.log("The student's name name is " + studentName);

Map keys can not be duplicated and we don't care about their order, so we use a Set to represent them.

Map values can be duplicated, but their order isn't significant. These are represented by an Array.


Keys, Values, and Entries

To look at a Maps keys, we call its keys method:

const studentIds = students.keys();
console.log("The student IDs are " + studentIds);

To look at a Map's values, we call its values (Surprise!) method:

const studentNames = students.values();
console.log("The student names are " + studentNames);

If we want to iterate over all (or many) of the entries in a map, looking at both key and value, it is intuitive to do something like this:

for(let id of students.keySet()) {
  console.log("This student's name is " + students.get(id));
}

The problem with this approach is that it will result in poor performance. (This is a common interview question.) This is because looking up the value for a key requires effort, and this code would look up the value for every key.

If we want to iterate over all keys and values, we do something like this instead:

for(let entry of students.entries()) {
  console.log("The student's id is " + entry[0]);
  console.log("The student's name is " + entry[1]);
}

Other Useful Map Methods

method what does it do?
delete(key) removes the entry associated with key
has(key) returns true if this map contains the key
size() returns the number of entries in the map
clear() removes all entries from the map

WeakMap

JS also has the concept of WeakMaps. These operate almost the exact same way as our standard Maps. The biggest difference is that these Maps can only have Objects as keys NO PRIMITIVES. There are also fewer methods available:

method what it does
delete(key) removes entry
has(key) returns boolean value for existence of key
get(key) returns value associated with key
set(key, value) sets given value to assigned key (must be object)