 Hello and welcome back. In this lecture, we are going to study about the template class map as part of the C++ standard library. Here is a quick recap of some of the topics we have already studied and that are relevant to this lecture. We have been studying about object oriented programming with structures and classes. We have studied about template classes and functions and we have looked at two specific classes in the C++ standard library, the string class and the vector class. In this lecture, we are going to look at a third class in the C++ standard library. This is the template class map. Much of this lecture is motivated by the treatment in the book and introduction to programming through C++ by Abhiram G. published by McGraw Hill education in 2014. Now the map class as it comes in the C++ standard library is actually used for representing what are called associative one-dimensional arrays or vectors. So what are associative arrays? These are basically arrays in which the index is not necessarily an integer but it could be an object of a specified type. For example, I could use a string as an index into an associative array or I could use a three-dimensional vector, which is an object of the class V3 that we have already studied as an index into another associative array. So here, for example, I have shown two arrays. The first one can be thought of as an array of double values, marks of students, which is going to be indexed by the names of the students, which are strings. The second one can be thought of as an array of three-dimensional vectors representing positions. So this is really an array of values of the type V3, where V3 is the class that we have studied earlier. And the index of this array could be a string giving the number of a flight. So this could represent the position of a flight as a three-dimensional vector indexed by the flight number. Now the notation that we are going to use when discussing about associative arrays is that we are going to talk about the index also as a key. And then of course when I index the array by the key, I get a value. So for example here, sham is the index and marks indexed by sham would be the value. Similarly, BA207 is the index and the position indexed by BA207, which is an object of class V3, would be the value. Now in an associative array, the type of the key and the type of the value are completely independent. So it is not necessary that the type of the key be related to the type of the value. But what is very important is that the key values must be ordered by a less than operator, which could be defined by overloading the usual less than operator. We will see more about these in the subsequent slides. So the map class will be used for representing and manipulating associative one-dimensional arrays or vectors. This is actually a template class and can be instantiated with a type for the key and a type for the value. Internally, the elements in an object of the map class will be stored as key-value pairs and all of these elements will be sorted by the keys. The internal representation of objects stored in a map class is really a binary search tree. So the different key-value pairs are actually going to be internally stored as a binary search tree. We have studied about binary search trees in an earlier lecture. And of course, this is going to dynamically allocate and deallocate memory, but the whole of dynamic memory management is built in and as a user of this class, you do not need to worry about it. Like vectors, map objects are basically container objects. They are used to store a collection of objects of some other type. And in a C++ program, if you want to use the map class, you must use hash include map at the start of the program. Now the map class actually has a large collection of member functions. In this lecture, however, we'll get to see only a small subset of them. And I encourage all of you to look up the entire collection of member functions of the map class in the handout that will be provided. Now while talking about the map class, it is also important to talk about the pair template class, which also comes in the C++ standard library. Now the pair template class has two data members named first and second. This class can be instantiated with two data types, T1 and T2. And the data member first has the type T1 and the data member second has the type T2. Now why are we discussing about the pair class when talking about maps? This is because whenever you define an object which is of the map class in which the type of the key and the type of the value has been instantiated with specific types like strings and doubles maybe. This object is really a collection of key value pairs as we have just seen. And these key value pairs are going to be stored as objects of the class pair. So this pair template class will be instantiated with the key type and value type, which is the same key type and value type that you use to instantiate the map class. And every key value pair that is stored in a map object is really an object of the class pair instantiated with key type and value type. So this is why you see that it's important to understand pair class when you're talking about the map class. Now here is a simple program that uses the map class. Note that I have said hash include map here. I've also said using namespace std because all the member functions of the map class and indeed the map class itself is in the namespace std. Now in this program I have declared an object marks which is a map with key of type string and value of type double. And thereafter I have st name which is a variable of type string and st marks which is a variable of type double. And here I have a loop and in this loop I ask for the name of a student, read in the name of a student and if the name of the student is input as end, then I print out buy and break from this while loop and come out and execute the remainder of the code. Otherwise if you give the name of a student which is not end, then I will ask, give the marks of the student. I will read in the marks and note what I am doing here. I am actually storing the marks of the student in this map indexed by the name of the student. So here string the first parameter when I am instantiating the map class is the type of the key. The second parameter when I am instantiating the map class is the type of the value. This is the name of the map and when I declare this I am basically creating an empty map of string comma double pairs. And when I do this assignment I am basically accessing an element in the map named marks and I am accessing this element by using the index st name which is a string. And here I am basically storing st marks along with the key st name in the map named marks. So that is exactly what is happening here. If the key value pair with key matching st name does not exist in the map marks, then I am going to create a new key value pair where the key will have the value st name and the value will have the value st marks. I will create this new pair and I will add it to the map marks. However, if a key value pair with key matching st name already existed in marks, then what am I going to do with this assignment? I am simply going to update the value of this pair. The key stays unchanged at st name. I am simply going to update the value of this pair to st marks and the previous value is going to be erased. So what happens if we execute the following two statements? In the first statement, I am assigning st marks to marks indexed by st name and in the next statement, I am assigning st marks plus 10 to the marks indexed by st name. So when I execute this statement, depending on whether there is already a key value pair with key matching st name, I may either insert a new key value pair. If such a key value pair with key matching st name did not exist, then I will insert a new key value pair with the key being st name and the value being st marks. Or if a key value pair already existed with key matching st name, then I am going to update the value of that pair with st marks. So this statement is either going to create a new key value pair or it is going to update an existing key value pair. However, when you execute this statement after the previous statement, this is certainly not going to create a new key value pair because you have already created a key value pair with key being st name over here if it did not exist. And so over here, you are simply going to update the value in the key value pair where key matches st name and the value would be updated to st marks plus 10. So we have seen how to write elements in a map. How do we read elements from a map? It is pretty much the same. Here I have a program which looks similar to what we had earlier, except that here I am taking from the user the name of the student and instead of writing the marks of the student in this map indexed by the name of the student, I am going to read out the marks of the student from this map indexed by the name of the student. So here is where I am printing it out. I am saying marks of the student is and I am indexing the map marks with the name of the student which is a string and when I do this indexing, I will get the value which is a double quantity and that will get printed out. Well, a few questions are relevant here that if the map marks already contained a key value pair where the key matched st name, then of course this will give me the value associated with that key. However, what if st name was say Abdul but there was no key value pair with key matching Abdul in the map named marks, then what is going to happen? Well, the C++ standard says that in that case, if there is no key value pair with key matching Abdul, then in trying to read this, a new key value pair will be created, the key of that pair will be said to Abdul and the value of that pair will be said to whatever the default constructor of the value type returns. Now, here the value type is double. The default constructor of double does not return any specific value for the object of type double. So, it basically contains garbage and therefore when I am trying to read this marks here using a string which does not appear as the key of any key value pair in this map, I will basically end up creating a new key value pair with the key set to Abdul and the value set to garbage. That is because the default constructor of double returns garbage. It does not initialize the double valued object. So, here when I am trying to read it out, basically this pair is first going to get created and then I am going to read the value from that pair and therefore I will get garbage and that is what is going to get printed out over here. So, this is important that in trying to read an element from the map, if that element did not exist, I will end up creating that element, initializing the value by whatever the default constructor returns and I am going to read that value which in this case happens to be garbage. Well, just like for vectors, I can also access elements of a map using the at member function. So, I could say marks.at stname instead of marks stname and just like we had seen for vectors, there is a subtle difference between accessing an element in these two ways. For example, if stname does not match the key of any key value pair in marks when you use the at member function, an out of range exception is going to be thrown whereas over here an out of range exception is not going to be thrown. Well, we have already studied that the key value pairs in a map are going to be stored sorted by key values. Now, in order to sort the key values, you require a comparison operator and what is preferable is that you have a less than operator defined for the key type. For example, when we said marks is a map where the key type is string and the value type is double for the class string, the less than operator is already predefined in the string class and in fact, this is the lexicographic or dictionary order. For example, the string Abdul will be considered less than the string Ajanta will be considered less than the string Bobby because in the dictionary this appears before this and that appears before Bobby. So, when we use the string class, we got this for free because it was already predefined in the string class. What if the less than operator is not predefined for the key type? Well, then you have to custom define the less than operator by using operator overloading. So, you have to create a function operator less than either as a member function of your class or as a non-member function. So, here I have shown it as a non-member function. This operator less than function must take two elements both of key type and it must return a Boolean true or false telling us when one key is less than the other key. There are certain properties that this less than ordering that we are defining through this operator must satisfy. For example, we must ensure that this ordering is transitive and anti-symmetric. What does transitive mean? It means if an object A is less than object B, if the object B is also less than object C, then the object A must be less than object C. That is what transitivity means and what does anti-symmetricity mean? It means that if an object A is less than object B, then it must not be the case that the object B is less than object A. In addition, this order defined by the less than operator must also ensure that every pair of distinct keys are ordered. For example, if A and B are distinct keys, then I should either have A less than B or I should have B less than A. Now, you could also define separate comparison functions, not the operator less than function, but a separate custom defined comparison function and when you are declaring your map, you could include the definition of this comparison function in the map declaration. However, we will not cover this in our discussions. We will just say that it is preferable to use the less than operator and if that is not already defined for the key type, it's a good idea to define this operator explicitly either as a member function or as a non-member function. Now, we've already studied about iterators. So, in the map class also we can have iterators and here are some iterator related functions in the map class. For example, I could have begin and end member functions and here is a simple program where I have declared a map which has key type string and value type double and then I have initialized this map object. In this manner, I have set marks of Ajanta is 10, marks of Bobby is 15 and marks of Abdul is 25 and now I have created an object I.T. which is an iterator of the map with key type string and value type double and I'm going to use this iterator to iterate through this map. So, I'm going to say it is marks dot begin. This will return an iterator or an abstract pointer to the first element in the map. Now, what is going to be the first element in the map? Remember that the key value pairs in this map marks are going to be stored sorted by the key. The key here is a string. So, we are going to sort the strings lexicographically and Abdul will come before Ajanta and Ajanta will come before Bobby. So, when we try to iterate through this map, through this iterator, we will first encounter the pair Abdul 25, then Ajanta 10 and then Bobby 15. And inside this for loop, what am I printing out? Recall that we had said that every object which is a map basically stores a collection of pairs where the pair has two data members, first and second. The first is going to be the key. The second is going to be the value. So, here basically I'm printing out the first and the second, which means the key and the value for the different key value pairs in map. And note also that IT is an iterator. So, it's like a pointer. So, I'm using the arrow operator to access the first and second data members of the pair, which is storing the key value pair in the map named marks. So, what do I expect to see here when this is executed? So, noting that these are basically the key and the value I expect to see in sorted order of the keys. What we'll get printed is Abdul 25, Ajanta 10 and Bobby 15. Just like for vectors, I can also have Arbygan and Aran member functions. So, for the same example, if I use the reverse iterator of the map class with key type string and value type double and then if I iterate using the reverse iterator, then just like for vectors, I will basically be printing out the ordered sequence of key value pairs in reverse order. So, I'll first print out Bobby 15, then I'll print out Ajanta 10 and then I'll print out Abdul 25. How do I find if an element exists in a map? Well, there is a special member function called count. So, I could read in the name of a student which will serve as a key and I could ask how many key value pairs are there, what is the count of key value pairs in which the key matches the name that I have read in. So, basically this function is going to count the number of pairs in which the key matches the name that I have read in and it's going to return 1 if the map contains an element with key st name, otherwise it will return 0. So, why is it 1? Because in a map, we want all the keys to be distinct, so therefore, there should only be one key value pair with a particular value of the key. So, if I see that marks.count st name is greater than 0, it means that there is a key value pair in the map named marks in which the key matches st name. So, I could then read out the marks from there and print it out, otherwise I could say that there is no student with the name st name. Now, there is an alternative way of finding out if an element exists in a map. This is by using iterators. So, here is another member function called find and if I say marks.find st name, it will actually return me an iterator which is an abstract pointer to the key value pair with key matching st name. Of course, this is only if there existed a key value pair with key matching st name. If there did not exist a key value pair with key matching st name, it will return me marks.end which is if you recall an iterator or an abstract pointer that points to the element beyond the last element in the collection of key value pairs. So, if the iterator that is returned by marks.find st name is not equal to marks.end, it means that I have actually found a key value pair with key matching st name. So, I can then print out the marks as it arrow second, otherwise I can say that there is no student with the name st name. How do I find how many elements there are in a map? Well, this is pretty simple. We have the size member function. So, in this particular case, I created a map with key type string and value type double, then I inserted three elements in it and now if I try to find out the size of it, I will get the sizes three. After that, I inserted one more element with key value Alex and when I said marks, note that there was already a key value pair with key agenta. So, this will not insert a new element, but it will simply update the existing element. It will update the value of that key value pair from 10 to 11. So, now I have only one additional key value pair. So, now if I try to print out the marks, I will get the sizes four. How do we delete elements from a map? Well, this is done through an iterator. So, for example, here I have created a map named marks and then I have inserted three elements in it and then I have said, please give me an iterator which points to the key value pair where the key matches Abdul and once I get that iterator, I could call marks dot erase with that iterator and that will delete or erase that key value pair to which this iterator was pointing to. I could also erase a key value pair by directly specifying the value of the key. So, in this case, I have basically deleted two key value pairs from the map marks. So, now if I try to print out its size, earlier it had three elements, two have been deleted, so I will get sizes one and if I actually try to print out the elements, there is only one element remaining now which is Ajanta having marks 10. So, this will print out Ajanta 10. Now, we have seen maps of simple data types, but map is really a template class and so I could indeed form maps of complex data types by instantiating the generic type to complex data types. So, here is an interesting example. For example, I could declare an object flight position which is a map with key value string and data value v3, a three-dimensional vector. So, given a flight name or a flight number as a string, this could return me the three-dimensional position of that flight and here is another map which says timed flight position. Here, given the name or number of a flight which is the key string here, what it is going to return as a value is another map and this map is going to take a key as double and it is going to return me a three-dimensional vector. So, here given the name or number of a flight, I am going to get a map and then in that map I could give the time and then it would give me the three-dimensional position of that flight. So, note that I have used map double, v3 as the type of the value within another map and note also here that I need the space here because if I don't put the space, these two greater than signs will look like what I use when I read in values from the standard input. So, it's important to put the space here otherwise the compiler will complain. So, in summary, in this lecture, we studied about the map class and its usage. However, we were able to study only some of its features. There are several more features and I encourage you to read about these from the handout. Thank you for your attention.