 Welcome back, in the previous segment we discussed a simple solution based on manual algorithms for our max display problem. Next we are going to turn to somewhat more sophisticated solutions. So to motivate those let us consider the drawbacks of the previous solution. So both queries are going to be too slow if the number of students, number of subjects is very huge. Say if you are going to do this for your entire university then you will notice that the previous solutions will be quite slow. The marks query is slow because we go through the entire RSM tab on every query. So we want to look for the marks of a given student but we go through the marks, all the marks of all the students. Now if we sort RSM tab by roll number and subject we can use binary search to find the marks. So we know this idea and if we implement these ideas then we will be able to speed this up. The rank query we calculate averages on every query. So if I want the rank for a certain roll number we calculate average marks obtained by all ranks. If we then need to find the rank of some other roll number we again go through the entire process. So the natural question is why do not we do this once at the very beginning and then just store those things. In fact once we have calculated the averages calculating the ranks itself is just one additional step and again why should we repeat, why do not we do that at the very beginning it will save us quite a bit of time while processing the queries themselves. So that is another thing that we should really be doing. Now there is another approach besides sorting and binary search which will work. So sorting and binary search will work but we want to suggest one more approach and this approach is going to be based on maps. Maps effectively produce the effect of sorting and accessing maps happens really by a process like binary search. In fact sometimes it is even faster than binary search but let us say it is sort of as good as binary search. So effectively what happens is that if we use maps we are going to get speed as well as coding simplicity. So let us first look at the marks query. So let me remind you what the query was. The query was M followed by roll number followed by subject code and of course you could have given the name but that is a minor matter. So let us just focus on M followed by roll number followed by subject code. Given a roll number and a subject we want to return the marks. Now if there was just one subject what would you do? Well since we know about maps we could just use a map from roll numbers to maps. What can we do for multiple subjects? Well we can use a map so the index will be a roll number and the value that the map produces for us could be something like all marks of the student. So subject wise marks of the student. So the value that is produced is not one mark but all marks. So maybe it produces a vector. So what do we do with all these marks? How do we go from all these marks to the marks in a particular subject? Well a natural idea will be to use another map because what are these subject wise maps anyway? So they are telling us that say in mathematics the marks are so many for this given roll number, for this fixed roll number, in physics the marks are so many, in English the marks are so many. So this is again a map. So the output of this map which where the index is roll number is should naturally be another map. So effectively what we are going to do is we are going to use a two level map. So let us see how this works. So the level in map let us call it marks and marks of roll number the value produced by this map is itself a map. And what is this? It is a map which gives marks of any subject given a roll number. So given a roll number means the index for this map, for this map that is returned by this map is the roll number. So the overall map is as follows. So the two level map is also going to be called marks but if we just supply one index to it it is going to give us a map and if we supply the second index which is the subject then it will give us the marks for the given subject for the given roll number. So how will we declare something like this? So the declaration is the first index type, the first index was a roll number. So whatever type we are going to have for the roll number we are going to place over here and the first, the overall thing is a map which takes a roll number and produces a value but the value is itself a map. But what is this value? It is a map from a subject type to a marks type. So we are going to have two indices, the second index is going to be a subject index and the value that that returns is going to be a marks type. Now in our case roll number type and subject type are both string and marks type is a double and so the actual declaration is this. So map string, map from string to a map from string to double and if you remember we have to put a space over here because if we do not then C++ will interpret it as the input redirection operator. We do not want that to happen. So this is the type declaration for our map. It really is similar to vector of vector of T and just as this is a matrix or this is accessed using two indices, this is also accessed using two indices. So what is the solution for this query or the entire thing actually, let us start with the entire thing first. So the main program you will see is going to be unchanged and in a sense we should expect this because the changes are at a low level. At a high level the query format remains the same and our main entities, our main tables are going to remain the same but the internals of the tables are going to be different. And well we are going to change the name of RnTab to nrTab for some reason which will become clear in a minute but this is only a cosmetic name change. The program really is unchanged and there are again only these two tables. And while we have not designated any member functions as public or private but if we were to and I guess once we are done we should designate some functions as public and private. So the public member functions will remain the same. So what are the public member functions for RnTab? So there was lookup here and for nrTab there was lookup and find rank. So those will remain the same but the private member functions that we had they will be different and even the data members will be different and the entire logic of these two tables is going to be different because now they are going to be using maps. So how does RnTab or what we are now going to call nrTab work? So it will now hold a map instead of a vector. Now maps have a direction from index to value and we want this table to give us a roll number given a name. So the index is a name and the value is a roll number and therefore we are going to call it nrTab to say that it goes from name to roll number. And that is it, that is the only reason why we are changing a name. So nrTab is a better name and for some reason which will become clear a little bit later we are going to keep the reverse map also but that is not going to be the main map. So in fact we will call it the reverse map. So to know what is reverse and what is forward it is important to give nrTab as the name for the entire thing. So we will see the details soon, in fact immediately because now we are going to look at the unchanged main program and our main first major entity nrTab. So this is our second marks display program and I have called it marks 3. Sort of marks 2 would have used binary search and sorting but we have skipped that and we have gone directly to version 3. So let me show you the main program first. The main program really has remained the same except for this name. The name is nrTab rather than rntab. So let us now look at this entity nrTab. So here is our entity nrTab. So as I said it is going to contain a table which is a map now and it is a map from string to string but it is a map from name to rule number and we will also keep a reverse map and we will call it revTab and it will give the name given the rule number. So what does, how do we construct nrTab? So the data is going to be taken from rn file which was a stream corresponding to the file opened already in the main program and we are going to go through this file or go through this stream and as before we are going to read the pairs rno and name. So we need the, read the rule number into rno and if we find that the file has ended then we break. Otherwise we read in the name and we store in the table the rule number corresponding to the name. So now this is a map and so we can just store it in this manner. And by the way even here we are assuming that the names are single words. So as indicated earlier you can do a little bit more work to make, to deal with the case where the names are longer and contain spaces. In the reverse tab we are going to store the rule number as the index and the name as the value. And now what does lookup look like? Well as before we are going to supply it an argument which could either be a rule number or a name. So we are going to check is this, does this appear as an index in the forward table. And for that we just had to ask tab of count of this greater than 0. If it is then we know that it is appearing as an index in the forward table. So that is it is a name. So in that case we are going to return tab of this index. Otherwise we are going to check does it appear as the index in the reverse table. The reverse table has roll numbers as indices. So if this does appear we are still going to return that itself but why we are doing this? We want to know whether this is a valid roll number. So if it is a valid roll number then we will return itself. If it is not a valid name or not a valid roll number then we are going to return the empty string. So this is exactly, this return protocol is exactly like the protocol that we had in the previous implementation as well. Now I want to make a comment over here. In this reverse table we are not using in any sensible way, we are not really indexing into it. We are just checking whether the given string appears as a proper index or we are checking whether this given string is a member of the set of indices, is one of the indices in the set of indices in this table. Now for this we could have used the set data structure from the standard library and that is a simpler data structure. But I use the reverse map since we have not really learned about it. You could keep this implementation or you could learn the set data structure and in fact now that you are coming to the end of the course you could get into the habit of looking up new things when you hear about them. So this is something that you could try out. In any case I have told you how NRTab is organized and you can see that it is actually simpler because the whole searching business is now gone and the map data structure, the map standard library structure takes care of all of that. So let us go back to the presentation. So let us now look at RSM tab. So RSM tab is going to hold two structures. So there is going to be a tab which is going to be the two level map which we talked about earlier into which the content of RSM file is read. But then as we discussed we are going to pre-compute all the ranks to begin with and so this is going to be stored again in a map. So its index is going to be the roll number and we are going to calculate, we are going to create this when we create the entire RSM tab. So we are calling it the RSM tab but internally it also contains a table for the ranks. So how RSM file is read is probably quite obvious by now. It is pretty much like how the RN file was read to create RN tab or NR tab, we will similarly read RSM file and create this first tab. How do we create the rank? So that is a little bit more interesting. So first we have to calculate the average marks for each student. So we have our tab and we want to add up the marks in tab of roll number. So what is tab of roll number? Tab of roll number if you remember is going to give you another map, it is going to give you a sub map. So what is that sub map? The sub map is going to be a map from subjects to marks. So this time we are going to, so we have the sub map gives us all the subjects that this particular roll number has taken and we are just going to add up those marks and divide it by the number of subjects. So this is how the sub map structure is actually coming in quite useful. And then we are going to store the roll number and average marks that we got over here into a vector called roll number average. So this is going to be a second, an additional data structure that we will need but this is going to be a very temporary data structure as we will see. So we will not put it up as a major thing over here. So we are going to store the roll number and average pairs into this vector. Then we are going to sort the vector. So we are going to sort the vector so that by average marks. And when this happens we will have the entries arranged in say we want decreasing order of average marks and so then we can go over these entries, pick up the roll numbers as they appear and those are the rank holders. So the earliest roll number is rank 1, then the next is rank 2 and so on. So at the end of this step roll number average will now contain roll numbers in order of ranks and so we can just enter them into the map called rank. So that is how all this is going to work. So let us now take a look at the code of RSMTab. And I want to tell you beforehand that it is going to contain the library class pair. So this pair is going to be used, this pair is going to be used, this is what is going to be stored in this roll number average, the vector roll number average. So let me just introduce this pair class a little bit, so what is the pair class? So the pair class contains two elements, after all it is a pair and it is really like a two element struct. So it is a two element struct that you do not have to, you can sort of define as you go along. But there are some important things that are already defined for pairs. So for example you can compare two pairs without actually yourself defining a comparison operator. If you have defined a struct then you would have to define the comparison operator but if it is a pair a comparison operator is implicitly defined. So how does this work? So if you are comparing two pairs then you first compare their x values then you compare their y values and if you find that the x value of one is smaller than the other then you declare that to be smaller. If only if they are equal, only if the x values are equal you move on to y. So here is another class and as I said this is a new class, I am going to show you the class and I am going to explain enough about the class but you should not get scared of seeing new things at this point. So here as I said you are pretty close to the end of the course and at this point you should have the confidence to be able to look up documentation. So see the online documentation on pairs to know more about that. So let us now go and look at the code for RSM tab. So let me just make this a little bit bigger. So as I said this RSM tab, so this is the structure RSM tab, our second major entity and we said that it contains this two level map called tab which will be indexed by first, the first index being the roll number, the second being the subject and then this is our rank map. So this given a roll number will return the rank. The construction of RSM tab is fairly straightforward, I am not going to go through it but let me just look at how the ranks are going to be created. So for that we have a member function called setup ranks. So this member function will use a local variable which is a vector and this will contain the pairs, the elements of this vector will be pairs and they will consist of a double under string. The double, the first element of the pair will hold the marks, sorry so the first element of the pair will hold is supposed to hold the average marks when they are calculated and the second element of the pair is going to hold the roll number. So how do we set up the ranks? So first we are going to go over the entire RSM tab, so RSM is going to be an entry in this table. So essentially we are going over each student. So remember that the first index of this is the roll number, so what we are picking out over here is an element of it, so which means for a fixed roll number we are going to get the entry. So we are going to set total to be 0 and we are going to calculate what the total marks are corresponding to every entry in this. So the roll number is going to be obtained by taking the first element, the first member of this pair, RSM itself is a pair just like these other pairs. So the first element is this RSM dot first, so that is the roll number and we are going to push on to this average rank, this part is going to be the average and this part is going to be the rank and this loop is going to be about calculating the average. So how do we calculate the average, well we are going to set total to 0 and then we are going to go over SM which is the second part of this RSM. So I think I should draw a picture over here, so tab was consisting of pairs, so the pairs we have called RSM, so there are several such pairs and this itself consists of pairs because remember it is a two level map, so these are SMs. So RSM consists of pairs, so what does our tab look like, so tab or rather I should say what does our tab look like, so tab you remember takes one index which is the roll number and the other index which is the subject. And so therefore if I look at RSM which is an entry of tab what does it look like, well this tab is a bunch of pairs, so what are the pairs in it. So each RSM looks like a roll number and then it looks like a map itself. So this is the first and this is the second entry in this pair. So when we over here when we fetch an element of this tab what we are getting is a pair like this. So we have got the roll number, so what we are doing in this loop is we will be calculating the average for a given roll number and then we are going to push that we are going to determine the rank for it, sorry we are going to determine the average for it and we are going to push it against the roll number. So our average rank vector will get the average over here and the rank over here. So as you can see that is the last step, so that is the last step in this first procedure. So in the first procedure we are, so at this point we have only calculated the averages and they are pushed on this vector. So how are they pushed, well this part is the roll number and this part is the average and this part is being determined over here. So let us see how it is determined. So RSM is all this, so RSM dot second is going to be this map, so what is this map? So this is a map from subject to marks, so it is pairs of this kind. So what is happening in this loop is that we are picking up each such pair. So SM is going to be a pair subject and mark. So SM is this, so total, we are going to create a total for this given roll number and we are going to add SM dot second to it, so SM dot second is the mark. So this we are going to add to total. So at this point after we have executed this entire loop what do we have? Well we have the total marks obtained by a given student in this variable total. So if you want the average we are going to divide total by RSM dot second dot size. So what is RSM dot second? RSM dot second is this entire thing, so it is subject mark, subject mark, subject mark for a given student. So how many such entries are there? So the number of such entries are the number of subjects. So in fact this quantity is simply is precisely the number of subjects. So we will indeed get the average marks over here and this is the roll number, so at this point this vector average rank will contain the average marks and the roll number. Next we are going to sort this vector, we are going to sort the average rank vector. So if we had just said the usual thing, sort average rank begin to end then we would have got the sorting in increasing order, we want it decreasing. So we pass it the function greater, the greater is equivalent to the operator greater than. So greater than, if we pass the greater than operator over here then we are going to get sorting in decreasing order, otherwise by default if we do not say anything the less than operator gets passed over here and therefore we get the usual sorting but we want the other sorting and since we want decreasing order we pass the greater than operator and I said earlier that all such operators are already defined on pairs and they are defined in sort of the lexicographic order that is they first sort on this field and then they sort on this field. So if this field is different then they sort on this field but what is this field? This is the average and so at the end of it this vector will be sorted on the average. It is sorted on the average so all I have to do is to go through this vector so we are going to examine every element of this vector and if I come to an entry of this vector what do I do? Well each entry the ith entry of this vector has two parts the first part is going to be the average marks and the second part is going to be the rank associated with that average marks. But I do not care about the average marks I care about the roll number and since this roll number average rank of I dot second appears at position I in this vector I know that it is rank must be I if I count rank starting at 0 but I want to count starting at 1 and therefore it is rank I am going to set to be equal to as I plus 1. So what now I get is that I can I have built up my rank table as well my rank map sorry over here so in my RSM tab I had this rank map and I have built it up as well. So that is it so that is what we have said that is what we need to know about this RSM tab and our find rank function is now extremely simple the calculation was already done and so the roll number appears in this as an index in this array we just return the rank that we already calculated otherwise we return minus 1. I guess we could have even here given that use the protocol of returning the string and we could have said not found but that is an improvement that you certainly should make to this code. So let us return to our presentation so as you can see the code is actually smaller than the previous implementations and that is because the library holds is not only faster but it is also a lot more compact the member functions for maps do a lot of interesting work they effectively do something like sorting and it is easier to understand actually because in some sense maps are intuitive I mean the notion of mapping an index to a value or this is quite easy to understand. So if you are having a difficulty with maps that is okay in some sense maps are a bit of an optional part of this whole course but I think many people will understand maps and if you do I think you should see how powerful they are and you should start using them when you code and by the way in this entire thing I have used maps but I could have used unordered maps as well so unordered maps will also be perfectly fine for all of this and I should again point out that the main program has not changed so in some sense this means that our decomposition of our logic into higher level and low level seems like a good decomposition. So let me make some concluding remarks so the main concern in this entire lecture was how to organize code so as to put everything in its right place why should everything be in its right place well it is like why should everything in the room be in its right place because if it is in its right place we know where we should be searching we know where we kept it where we know where we will find it that kind of thing then we should make functions small to improve readability we should make code self-documenting well of course we can write comments but and we have not discussed that but better than that is to write the code in a very obvious manner. So give the names of the functions give the names of the variables nicely so that the logic is very obvious. In addition to that we considered some additional principles so we said something like represent important entities using structures then we said that if there is an important action then you should have a function a named function doing it or a named member function doing it because then it is giving importance to that piece of code and giving it a name which helps in readability and we also said that the main program should indicate high level program structure and the details should get implemented in function calls. So that concludes this lecture and we will and you are invited to go over the code and you are invited to make the code even more readable and certainly you really should develop a taste and you do not have to you do not have to take my taste but you should develop a taste and you should have a notion of what is the right way to write this place of write this piece of logic and you should try to develop a consistent style so that at least you yourself will be able to find your code and hopefully you will it will be easier for other people also to understand your code and find things in it very easily. So we will conclude with that and thank you.