map, unordered_map...Nope, Vector Of Pairs!!

This personal experiment is something new to me. I have a 2d vector of maintenance codes. I wanted to iterate through parts(blocks of rows) of the 2d vector and get the maint. codes and their occurrences in the range of analysis. From that point, I need to sort the vector of pairs based on their occurrences, then create a 1d vector of just the maint codes in order of MOST occurrences to least. This is something I never came across before. I'm fairly new to programming and c++ is my first language. I'm self taught, which is difficult, especially without the help found in this forum. At first I thought of using a MAP. But, that would not serve the purpose, with the sorting issue. Then I thought of unordered map. After some research of unordered map, I saw something called "vector of pairs". Never heard of that before, and don't know that much about it.

So here is what I got. I have a sample of the 2d vector of maintenance codes. I have a vector of pairs set up with all possible 17 maint codes as the KEY, and 0 as the values(used for counted occurrences for the corresponding maint code. I want to iterate through rows [index] [2] thru [9]. Then ++values of the pairs with the maint code found. After all iterations are finished, sort the vector of pairs values and then create a single vector consisting of only the maint codes with Most occurrences to least.
The final vector should be as follows:
15 4 10 11 12 17 1 2 7 14 3 5 8 9 16 6 13

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>

using namespace std;
using Vec = std::vector<int>;
using Vec2D = std::vector<Vec>;

int main () {

    //  2d vector of maintenance codes codes can range from 1 to 17
    Vec2D mcvec {{2, 9, 12, 14}, 
                 {1, 7, 9, 16},
                 {2, 8, 10, 17},   //  Start Counting mcvec[2].begin()
                 {3, 7, 11, 15},
                 {1, 10, 14, 15},
                 {4, 5, 12, 17},
                 {1, 9, 15, 17}, 
                 {4, 11, 15, 16},
                 {2, 10, 12, 14},
                 {4, 7, 11, 12},    //  End Counting mcvec[9].end()
                 {2, 5, 11, 15}};
    
    //  vector of pairs  <key=maintenance code, value=counter for # of occurrences of code
    vector<pair<int, int>> mcprvec { {1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0},
                                     {7, 0}, {8, 0}, {9, 0}, {10, 0}, {11, 0}, {12, 0},
                                     {13, 0}, {14, 0}, {15, 0}, {16, 0}, {17, 0} };
    
    int x { 2 };  // Used for starting row [index] of mcvec
    int y { 10 };  //Used for ending row [index] of mcvec
    for ( int i { x}; mcvec[i] < mcvec[y] ; ++i )   // Not sure if these 2 FOR loops (lines 32, 33)are set up 
        for ( int j {y}; j < mcvec[i].size() ; ++j )    // correctly to iterate through the mcvec 2dvector.  
        // HERE i'm really stuck!   Not sure how to increase counter in mcprvec for when the key is present.

    return 0;    
}


Last edited on
This is unrelated to your question, but why do you start with the maintenance codes in a vector of vectors, rather than in a simple linear vector? All you do with mcvec is iterate it from start to finish.

Something easy you could do is, rather than populate the vector of pairs directly from mcvec, is go mcvec → map<int, int> → vector<pair<int, int>> → sort → display.
Last edited on
That is how the codes are presented. Its from a database/text file. Each row represents something different. The example above is only a very small example of the maint code file. I don't want to go from begining to end of the whole file, only blocks of rows. Sorry but its only a small example.
Fair enough.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;

using codeType = int;
using Vec = vector<codeType>;
using Vec2D = vector<Vec>;
using PR = pair<codeType,int>;


int main ()
{
   Vec2D mcvec { {2, 9, 12, 14}, 
                 {1, 7, 9, 16},
                 {2, 8, 10, 17},   //  Start Counting mcvec[2].begin()
                 {3, 7, 11, 15},
                 {1, 10, 14, 15},
                 {4, 5, 12, 17},
                 {1, 9, 15, 17}, 
                 {4, 11, 15, 16},
                 {2, 10, 12, 14},
                 {4, 7, 11, 12},    //  End Counting mcvec[9].end()
                 {2, 5, 11, 15} };

   map<codeType,int> freq;
   for ( int row = 2; row < 10; row++ )
   {
      for ( auto e : mcvec[row] ) freq[e]++;
   }
   
   vector<PR> maintFreq( freq.begin(), freq.end() );
   sort( maintFreq.begin(), maintFreq.end(), []( PR a, PR b ){ return a.second > b.second; } );
   for ( PR pr : maintFreq ) cout << pr.first << ' ';
}


15 4 10 11 12 17 1 2 7 14 3 5 8 9 16 
Last edited on
Last chance, thank you very much!! Sorry for the delay of getting in here. Not at computer today. Will give this a try later this afternoon. Is there a way of including the maint codes that have 0 occurrences? 6 and 13 should be on the end. I might be able to figure that out, just might not be as efficient as what you may come up with. I'm looking forward to trying this later on. Thanks again!
Last edited on
Brian845 wrote:
Is there a way of including the maint codes that have 0 occurrences? 6 and 13 should be on the end.


Sure - you can initialise the frequency table when you create it.
1
2
   map<codeType,int> freq;
   for ( codeType e = 1; e <= 17; e++ ) freq[e] = 0;


However, who's to say that the codes are always integers, or there are no codes 18, 19, 20, ...
Last edited on
Hey, lastchance. THANKS!!! Your code that you wrote works PERFECTLY! It would have taken me days to figure it out. I greatly appreciate your help. I ran the code as is first, then I initialized the map as above. I did find something QUITE interesting with initializing it with the code snippet posted above:
1
2
  map<codeType,int> freq;
   for ( codeType e = 1; e <= 17; e++ ) freq[e] = 0;

Using that initialization, the output is not the same, BUT it does give output of the same occurrences grouped together. Let me explain further. This output as posted with your original code:
15 4 10 11 12 17 1 2 7 14 3 5 8 9 16 
Is correct, and the maint codes that have the SAME value for occurrences are in lexicographic order. For example...4 10 11 12 17 all have the same occurrence which is 3. Then 1 2 7 14 have the same occurrences which is 2. NOW, initialize as stated above and run again. Here is the output I'm getting:
15 17 4 12 11 10 2 14 7 1 9 8 5 3 16 6 13
The codes are sorted by most occurrences to least, BUT codes that have the same occurrences are not in lexicographic order. Look how the 4 10 11 12 17 from the first output is represented in the second output 17 4 12 11 10. I'm not dissatified with those results at all. Just was wondering how that happened?? I kinda like it that way, as long as it will be consistent from run to run. If you have the time can you explain the WHY it changes things??

THANKS again!!
Brian

Last edited on
If you want to sort those with the same frequency then you will have to specify which order of maintenance code you want to come first. You can do that by adjusting the comparator that forms the third argument of the sort() function.
Got it! Thanks!!
Like so:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;

using codeType = int;
using Vec = vector<codeType>;
using Vec2D = vector<Vec>;
using PR = pair<codeType,int>;


bool sortOrder( PR a, PR b )
{
   if ( a.second == b.second ) return a.first < b.first;   // If equal frequencies, then in ascending order of maint code
   return a.second > b.second;                             // Otherwise, descending order of frequency
}


int main ()
{
   Vec2D mcvec { {2, 9, 12, 14}, 
                 {1, 7, 9, 16},
                 {2, 8, 10, 17},   //  Start Counting mcvec[2].begin()
                 {3, 7, 11, 15},
                 {1, 10, 14, 15},
                 {4, 5, 12, 17},
                 {1, 9, 15, 17}, 
                 {4, 11, 15, 16},
                 {2, 10, 12, 14},
                 {4, 7, 11, 12},    //  End Counting mcvec[9].end()
                 {2, 5, 11, 15} };

   // Generate frequency distribution
   map<codeType,int> freq;
   for ( codeType e = 1; e <= 17; e++ ) freq[e] = 0;
   for ( int row = 2; row < 10; row++ )
   {
      for ( auto e : mcvec[row] ) freq[e]++;
   }
   
   // Reassemble in linear data structure
   vector<PR> maintFreq( freq.begin(), freq.end() );
   cout << "Original counts:\n";
   for ( PR pr : maintFreq ) cout << pr.first << ": " << pr.second << '\n'; 
   
   // Sort
   cout << "\nSorted by frequency (descending), then maintenance code (ascending):\n";
   sort( maintFreq.begin(), maintFreq.end(), sortOrder );
   for ( PR pr : maintFreq ) cout << pr.first << ": " << pr.second << '\n';
}


Original counts:
1: 2
2: 2
3: 1
4: 3
5: 1
6: 0
7: 2
8: 1
9: 1
10: 3
11: 3
12: 3
13: 0
14: 2
15: 4
16: 1
17: 3

Sorted by frequency (descending), then maintenance code (ascending):
15: 4
4: 3
10: 3
11: 3
12: 3
17: 3
1: 2
2: 2
7: 2
14: 2
3: 1
5: 1
8: 1
9: 1
16: 1
6: 0
13: 0
Last edited on
That makes sense. Me personally, I like the unordered same frequency output. I'll have to see which way is best for the purpose it's being used. Thanks again!!
Topic archived. No new replies allowed.