0

I have a vector storing the most frequent words in a file. Initially the values was stored in a map of strings and integers but then I copied the map into the vector I thought it would be easier to sort. Then I realized that the std sort() function sorts the vector by the first key (string in this case). But I want to sort it such that the most used words at the top and the least used at the bottom.

#include <iostream>
#include <fstream>
#include <map>
#include <algorithm>
#include <vector>
#include <iterator>

using namespace std;

int main(){
  
  fstream fs; 
  fs.open("/Users/brah79/Downloads/skola/c++/codeTest/test.txt");
  string word; 
  map <string, int> list; 
  while(fs >> word){
    if(list.find(word) != list.end()){
      list[word]++; 
    }
    else{
      list[word] = 1; 
    }
  }

  vector <pair <string, int> > vector(list.begin(), list.end()); 

  sort(vector.begin(), vector.end() greater<int>()); 
  for(int i = 0; i < vector.size(); i++){
    if(vector[i].second == 1){
      cout << vector[i].first << " is repeated " << vector[i].second << " time" << endl; 
    }
    else{
      cout << vector[i].first << " is repeated " << vector[i].second << " times" << endl;
    }
  }



  return 0; 
}

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
brah79
  • 37
  • 5

1 Answers1

1

First of all, as mentioned in a comment, this is too complicated:

if(list.find(word) != list.end()){
  list[word]++; 
}
else{
  list[word] = 1; 
}

It looks up the key word twice, when it has to be looked up only once, because this does the same:

 list[word]++;

operator[] already does add a default constructed element if none exists in the map.

Then I see no reason to store the item you want to have sorted as first rather than second:

 std::vector<std::pair<int,std::string> v; // dont use same name for type and variable

 for (const auto& e : list) {  // with using namespace std there is no way to distinguish this from std::list  :(
     v.emplace_back( e.second , e.first );
 }

Now you can use std::sort with std::greater. Alternatively, keep the pairs as they are and write a custom comparator that compares std::pair(second,first).

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • error: no member named emplace_back in std::vector – brah79 Dec 02 '22 at 08:39
  • @brah79 `emplace_back` is available since C++11. You can use `push_back` too – 463035818_is_not_an_ai Dec 02 '22 at 08:41
  • I would suggest using C++17 [try_emplace](https://en.cppreference.com/w/cpp/container/map/try_emplace) method for asserting that the entry is present in the map and then using the returned iterator to increment the value. `list[word]++` it's short and does the work, but it's not explicit enough to be self-explanatory in the situations where there is no matching key in the map. – pintarj Dec 02 '22 at 09:34
  • @pintarj I suppose it is personal preference. I'd use `try_emplace` (or `insert`) only when I need to know if the element was present before or not. When I do not need this information I consider `operator[]` to be more clear – 463035818_is_not_an_ai Dec 02 '22 at 09:38
  • @pintarj imho `map::operator[]` is explicit enough about inserting an element. If one isnt aware of that one will write buggy code and be confused about other code. – 463035818_is_not_an_ai Dec 02 '22 at 09:41