C++

How to use C++ Unordered Map

A map, also known as an associative array is a list of elements, where each element is a key/value pair. So, each key corresponds to a value. Different keys can have the same value, for ordinary work. For example, the keys can be a list of fruits and the corresponding values, the colors of the fruits. In C++, the map is implemented as a data structure with member functions and operators. An ordered map is one where the element pairs have been ordered by keys. An unordered map is one where there is no order. This article explains how to use C++ unordered map, written as unordered_map. You need knowledge in C++ pointers to understand this article. unordered_map is part of the C++ standard library.

Class and Objects

A class is a set of variables and functions that work together, where the variables do not have values assigned to. When values are assigned to the variables, the class becomes an object. Different values given to the same class result in different objects; that is, different objects are the same class with different values. Creating an object from a class is said to be instantiating the object.

The name, unordered_map, is a class. An object created from the unordered_map class has a programmer chosen name.

A function that belongs to a class is needed to instantiate an object from the class. In C++, that function has the same name as the name of the class. Objects created (instantiated) from the class have different names given to them, by the programmer.

Creating an object from the class means constructing the object; it also means instantiating.

A C++ program which uses the unordered_map class, starts with the following lines at the top of the file:

#include <iostream>
#include <unordered_map>
using namespace std;

The first line is for input/output. The second line is to allow the program to use all the features of the unordered_map class. The third line allows the program to use the names in the standard namespace.

Overloading a Function

When two or more different function signatures have the same name, that name is said to be overloaded. When one function is called, the number and type of arguments, determine which function is actually executed.

Construction/Copy Constructing

Simple Construction

An unordered map can be constructed and assigned values as follows:

    unordered_map<const char*, const char*> umap;

    umap["banana"] = "yellow";
    umap["grape"] = "green";
    umap["fig"] = "purple";

The declaration begins with the template specialization with the types for the key and value pairs. This is followed by the programmer’s chosen name for the map; then a semicolon. The second code segment shows how to assign values to their keys.
Construction by Initializer_list
This can be done as follows:

unordered_map<const char*, const char*> umap ({{"banana", "yellow"},
 {"grape", "green"}, {"fig", "purple"}});

Construction by assigning Initializer_list
Example:

unordered_map<const char*, const char*> umap = {{"banana", "yellow"},
 {"grape", "green"}, {"fig", "purple"}};

Construction by copying another unordered_map
Example:

unordered_map<const char*, const char*> umap1 ({{"banana", "yellow"},
 {"grape", "green"}, {"fig", "purple"}});
unordered_map<const char*, const char*> umap2 (umap1);

The pair<type1, type2> Element

The following code shows how to create and access the pair element:

pair<char, const char*> pr = {'d', "sea"};
cout << pr.first << '\n';
cout << pr.second << '\n';

The output is:

d
sea

first and second are reserved words for the two items in the pair. The values in the pair can still be changed using first and second.

A pair is called, value_type in the topic of the unordered map.

unordered_map Element Access

mapped_type& operator[](key_type&& k)
Returns the value for the corresponding key. Example:

    unordered_map<const char*, const char*> umap;

    umap["banana"] = "yellow";
    umap["grape"] = "green";
    umap["fig"] = "purple";

    const char *ret = umap["grape"];
   
    cout << ret <<'\n';

The output is: “green”. Values can be assigned in the same way – see above.

unordered_map Capacity

size_type size() const noexcept
Returns the number of pairs in the map.

    unordered_map<const char*, const char*> umap;

    umap["banana"] = "yellow";
    umap["grape"] = "green";
    umap["fig"] = "purple";

    cout << umap.size() <<'\n';

Output is 3.

bool empty() const noexcept

Returns 1 for true if the map has no pair, and 0 for false if it has pairs. Example:

    unordered_map<const char*, const char*> umap;
    cout << umap.empty() <<'\n';

Output is 1.

Returning Iterators and the unordered-map Class

An iterator is like a pointer but has more functionality than the pointer.

begin() noexcept

Returns an iterator that points to the first pair of the map object, as in the following code segment:

    unordered_map<const char*, const char*> umap;

    umap["banana"] = "yellow"; umap["grape"] = "green"; umap["fig"] = "purple";

    unordered_map<const char*, const char*>::iterator iter = umap.begin();
    pair<const char*, const char*> pr = *iter;
    cout << pr.first << ", " << pr.second << '\n';

The output is: fig, purple. The map is un-ordered.

begin() const noexcept;

Returns an iterator that points to the first element of the map object collection. When the object construction is preceded by const, the expression “begin() const” is executed instead of “begin()”. Under this condition, the elements in the object cannot be modified. It is used in the following code, for example.

    const unordered_map<const char*, const char*> umap ({{"banana", "yellow"},
    {"grape", "green"}, {"fig", "purple"}});

    unordered_map<const char*, const char*>::const_iterator iter = umap.begin();
    pair<const char*, const char*> pr = *iter;
    cout << pr.first << ", " << pr.second << '\n';

The output is: fig, purple. The map is un-ordered. Note that const_iterator has been used this time, instead of just iterator, to receive the returned iterator.

end() noexcept

Returns an iterator that points immediately beyond the last element of the map object.

end() const noexcept

Returns an iterator that points immediately beyond the last element of the map object. When the map object construction is preceded by const, the expression “end() const” is executed instead of “end()”.

unordered_map Operations

iterator find(const key_type& k)

Searches for a pair of the given key in the map. If it is found, it returns the iterator. If not found, it returns an iterator that points to the end of the map, which is not a pair. The following code shows how to use this member function:

    unordered_map<char, char> umap;

    umap['a'] = 'b'; umap['c'] = 'd'; umap['e'] = 'f';

    unordered_map<char, char>::iterator iter = umap.find('c');
    if (umap.find('c') != umap.end())
        {
            pair<char, char> pr = *iter;
            cout << pr.first << ", " << pr.second << '\n';
        }

The output is: c, d

const_iterator find(const key_type& k) const;

This version of the function is called, if the creation of the unordered map begins with const, making all the elements of the map read-only.

unordered_map Modifiers

pair<iterator, bool> insert(value_type&& obj)
An unordered map means the pairs are not in any order. So, the program inserts the pair in any place it finds convenient. The function returns, pair<iterator, bool>. If the insertion was successful, bool will be 1 for true, otherwise it would be 0 for false. If the insertion is successful, then the iterator will point to the newly inserted element. The following code illustrates the use:

    unordered_map<const char*, const char*> umap;

    umap["banana"] = "yellow";
    umap["grape"] = "green";
    umap["fig"] = "purple";
   
    umap.insert({{"cherry", "red"}, {"strawberry", "red"}});

    cout << umap.size() << '\n';

The output is: 5. More than one pair can be inserted.

size_type erase(const key_type& k)

This function erases a pair from the unordered_map. The following code segment illustrates:

    unordered_map<const char*, const char*> umap;

    umap["banana"] = "yellow";
    umap["grape"] = "green";
    umap["fig"] = "purple";
   
    int num = umap.erase("grape");

    cout << umap.size() << '\n';

Output is 2.
void swap(unordered_map&)
Two unordered maps can be swapped, as illustrated in this code segment:

     unordered_map<const char*, const char*> umap1 = {{"banana", "yellow"},
     {"grape", "green"}, {"fig", "purple"}, {"strawberry", "red"}};

    unordered_map<const char*, const char*> umap2 = {{"cherry", "red"}, {"lime", "green"}};

    umap1.swap(umap2);

    unordered_map<const char*, const char*>::iterator iter1 = umap1.begin();
    pair<const char*, const char*> pr1 = *iter1;
    unordered_map<const char*, const char*>::iterator iter2 = umap2.begin();
    pair<const char*, const char*> pr2 = *iter2;

    cout << "First key and size of umap1: "<< pr1.first <<", "<< umap1.size() << '\n';
    cout << "First key and size of umap2 "<< pr2.first <<", "<< umap2.size() << '\n';
    unordered_map<const char*, const char*> umap1 = {{"banana", "yellow"},
   {"grape", "green"}, {"fig", "purple"}, {"strawberry", "red"}};
    unordered_map<const char*, const char*> umap2 = {{"cherry", "red"}, {"lime", "green"}};

    umap1.swap(umap2);

    unordered_map<const char*, const char*>::iterator iter1 = umap1.begin();
    pair<const char*, const char*> pr1 = *iter1;
    unordered_map<const char*, const char*>::iterator iter2 = umap2.begin();
    pair<const char*, const char*> pr2 = *iter2;

    cout << "First key and size of umap1: "<< pr1.first <<", "<< umap1.size() << '\n';
    cout << "First key and size of umap2 "<< pr2.first <<", "<< umap2.size() << '\n';

The output is:

First key and size of umap1: lime, 2

First key and size of umap2 strawberry, 4

The map is un-ordered. Note that the length of a map is increased if necessary. The data types must be the same.

Class and its Instantiated Objects

A value is to a data type, as an instantiated object is to a class. The unordered map construction can also accept a class as a data type. The following program illustrates this:

#include <iostream>
#include <unordered_map>
using namespace std;

    class TheCla
        {
            public:
            int num;
            static char ch;

            void func (char cha, const char *str)
                {
                    cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';
                }
            static void fun (char ch)
                {
                    if (ch == 'a')
                        cout << "Official static member function" << '\n';
                }
        };

int main()
{
    TheCla obj1; TheCla obj2; TheCla obj3; TheCla obj4; TheCla obj5;

    unordered_map <const char*, TheCla> umap;
    umap = {{"banana", obj1}, {"grape", obj2}, {"fig", obj3}, {"strawberry", obj4}, {"lime", obj5}};

    cout << umap.size() << '\n';

    return 0;
}

The output is: 5.

The class definition has two data public members and two public member functions. In the main() function, different objects for the class are instantiated. An unordered map is then instantiated, where each pair consists of the name of a fruit and an object from the class. The size of the map is displayed. The program compiles with no warning or error message.

Application of the Map

The array associates an index to value. Key/value pairs exist in many situations in life, which can be programmed. The key/value pair of fruit/color is just one example. Another example is the name of people and their ages. In this case, the pair will be of a type, pair<const char*, float>. It can also be pair<string, float>. In the latter case, the pre-processing directive will be employed. A key/value pair can still be the names of married couples. In countries where there is polygamy, there will be different wives for one man.

Formation of a Map

A map is not a two-dimensional array, with two columns. A map works with a hash function. The key is encoded by the hash function, into an integer of an array. It is this array that holds the values. So, there is actually one array with the values, and keys are mapped to the indices of the array, and so the correspondences between keys and values are made. Hashing is an extensive topic and is not covered in this article.

Conclusion

A map, also known as an associative array is a list of elements, where each element is a key/value pair. So, each key corresponds to a value. In C++, the map is implemented as a data structure with member functions and operators. An ordered map is one where the element pairs have been ordered by keys. An unordered map is one where there is no ordering.

Technically, a hash consists of pair<type1, type2> elements. In fact, the pair is a whole data structure with its member functions and operators. The two template parameters for the pair are the same two template parameters for the unordered_map.

The initializer_list for the map is an array literal of literals. Each internal literal consists of two objects, the key/value pair.

The member functions and operators for unordered_map can be categorized under the following headings: unordered_map construction/copy constructing, unordered_map Capacity, unordered_map iterator, unordered_map Operations, and unordered_map Modifiers.

An unordered map is used when a key has to be mapped to a value.

Chrys

About the author

Chrysanthus Forcha

Discoverer of mathematics Integration from First Principles and related series. Master’s Degree in Technical Education, specializing in Electronics and Computer Software. BSc Electronics. I also have knowledge and experience at the Master’s level in Computing and Telecommunications. Out of 20,000 writers, I was the 37th best writer at devarticles.com. I have been working in these fields for more than 10 years.