print map values in descending order in c++ - c++

I have a map input which contains a list of words and their counts.
I use this function to print the map input:
template <class KTy, class Ty>
void PrintMap(map<KTy, Ty> map)
{
typedef std::map<KTy, Ty>::iterator iterator;
for (iterator p = map.begin(); p != map.end(); p++)
cout << p->first << ": " << p->second << endl;
}
it prints the values likes this:
you : 296
she : 14
go : 29
how can I print it in descending order of word count.

Try the following:
// Copy it into a vector.
std::vector<std::pair<std::string,int>> vector( map.begin(), map.end() );
// Sort the vector according to the word count in descending order.
std::sort( vector.begin(), vector.end(),
[]( const auto & lhs, const auto & rhs )
{ return lhs.second > rhs.second; } );
// Print out the vector.
for ( const auto & item : vector )
std::cout << item.first << ": " << item.second << std::endl;
The map is sorted according to the keys, i. e. alphabetically. You cannot change that behaviour. Therefore, the easiest way to get the job done is copying it into a vector and sorting it with a user defined compare function.

map stores elements sorted by key not by value. Unless you want to change the type of your map, the only way to do it is to sort your elements after getting them out. I think the easiest way to do so is via std::sort
Given that dereferencing an iterator into a map gives a const value_type&, we can take advantage of the reference to avoid actually creating copies of value_type (which is a std::pair<Key, Value>). However, the code will be a little longer than if we wanted to copy:
template <class KTy, class Ty>
void PrintMap(const std::map<KTy, Ty>& map)
{
using vt = const typename std::map<KTy, Ty>::value_type*;
std::vector<vt> vec(map.size());
size_t i = 0;
for(const auto& keyval : map)
{
vec[i++] = &keyval;
}
std::sort(std::begin(vec), std::end(vec), [](vt _lhs, vt _rhs){return _lhs->second > _rhs->second;});
for(const auto& el : vec)
std::cout << el->first << ": " << el->second << std::endl;
}
With a test
std::map<std::string, int> myMap{{"you", 296}, {"she", 14}, {"go", 29}};
PrintMap(myMap);
Outputs
you: 296
go: 29
she: 14
This should be much faster if your map is of non-trivially copyable elements.

Put data in another container, sort by word count, print.

Related

What is the correct way to move key-value contents from the first map to the second(value-key) map?

I am trying to count the most common words in text, so firstly i am filling the map of <word, count>, secondly I am trying to move the contents of the map <word, count> to the multimap<count, word>. But there is the problem: node type of STL maps/hashes are <const Key, Value>. I have tried to const_cast, it worked, but it seems ugly and UB'ly. Are there any another ways to move the contents?
int main()
{
std::unordered_map<std::string, std::size_t> words;
std::multimap<std::size_t, std::string> sorted_ordered_words;
std::for_each(std::istream_iterator<std::string>{std::cin}, {}, [&](const std::string& str)
{
++words[str];
});
std::transform(std::make_move_iterator(std::begin(words)),
std::make_move_iterator(std::end(words)),
std::inserter(sorted_ordered_words, std::end(sorted_ordered_words)),
[](decltype (words)::value_type && v)
{
return std::make_pair(v.second, std::move(const_cast<std::string&>(v.first)));
});
for (const auto &[count, word] : sorted_ordered_words)
{
std::cout << count << " - " << word << std::endl;
}
return 0;
}
A well defined way to move the string from the original container is to extract the node it is in first. That exposes a non-const reference to the key.
for (auto it = words.begin(); it != words.end();) {
auto copy = it;
++it;
auto node = words.extract(copy);
static_assert(std::is_same_v<decltype(std::move(node.key())), std::string&&>);
sorted_ordered_words.emplace(node.mapped(), std::move(node.key()));
}
Using const_cast is definitely UB because the keys are just moved from but are still in the map, violating internal constraints (all strings are the same, "", when they should all be unique). This could lead to crashes in the destructor for example.
If it's just for printing in order, you don't need to build a multimap. It's faster to just sort a vector of pairs rather than inserting into a multimap one by one.
std::vector<decltype(words)::value_type*> vec;
vec.reserve(words.size());
std::transform(words.begin(), words.end(), std::back_inserter(vec), [](auto& v) { return &v; });
std::sort(vec.begin(), vec.end(), [](auto* l, auto* r) {
return l->second < r->second;
});
for (const auto* item : vec) {
const auto& [word, count] = *item;
std::cout << count << " - " << word << std::endl;
}
You could also use std::vector<std::pair<std::size_t, const std::string&>> and sort by .first.

Search Map & Print Vector

I have an STL map that maps a key to a vector of deliverables.
I would like to search the map for a certain key and print out all of the deliverables. I am trying to iterate through the vector and call print on each item.
typedef std::vector<Deliverables> MyDeliverables;
typedef std::map<int, MyDeliverables> MyMap;
MyMap map1;
template < class T >
void printVector( const vector <T> &v)
{
for (auto p = v.begin(); p != v.end(); ++p)
*p->print();
}
int main()
{
Deliverables del("Name", 12, 12, 2018);
map1.insert(MyMap::value_type(1, MyDeliverables()));
auto search = map1.find(1);
if (search != map1.end()) {
std::cout << "Found Student ID: " << search->first << '\n';
printVector(search->second);
}
else {
std::cout << "Not found\n";
}
}
Error C2662 'void Deliverables::print(void)': cannot convert 'this' pointer from 'const Deliverables' to 'Deliverables &'
Line: *p->print();
How can I correctly print the deliverables?
The issue is with the code you are not showing:
Deliverables::print()
It is not const, so you cannot use it. Declare the print function as const, and then you can use a const Deliverables&:
Deliverables::print() const
Then change your loop to avoid confusion as to what to dereference and how many times:
for(const auto& p: v)
p.print();

How to count how the number of elements stored in a vector which is stored in a map

I have four static vectors. In my .cpp file (not my .h file!) I define these vector as such:
std::vector<Object*> ClassA::vecA;
std::vector<Object*> ClassA::vecB;
std::vector<Object*> ClassA::vecC;
std::vector<Object*> ClassA::vecD;
Then I populate each of these vectors with a number of objects of type Object.
Next I create a map:
std::map<std::string, std::vector<Object*> > cntr;
I populate this map with the vectors from above and a string as a Key for each vector.
The question is, how do I access the vectors in the map to find out the number of elements they contain. I have tried:
for (it = Cntr.begin(); it != Cntr.end(); it++)
{
if (it->first != token)
{
std::cout << it->first << std::endl;
int i = (it->second).size();
std::cout << "SIZE: " << i << std::endl;
}
}
However i always gives me the value of 1. What is the correct approach?
First off you need to set the iterator to point to an valid element of the map. When you do
std::map<std::string, std::vector<Object*>>::iterator Class::it;
int size = it->second.size();
it doesn't point to anything so using it is undefined behavior. What you can do though is use
std::map<std::string, std::vector<Object*>>::iterator Class::it;
it = cntr.begin();
int size = it->second.size();
Which now gives you the size of the first vector in the map.
If you want to get all of the sizes then you will need to iterate through the map. You can do this with a nice ranged based for loop like
for (const auto & elem : cntr) // get a const reference to each pair
std::cout << elem.second.size();
NathanOliver's answer should work if you have C++11. If you don't, you can try this, with a typedef to make the code clear:
typedef std::vector<Object*> MypObjVec;
typedef std::map<std::string, MypObjVec> MyMap;
MyMap::iterator Class::it = cntr.begin();
const MyMap::iterator Class::it_end = cntr.end();
for(; it!=it_end ; ++it)
{
std::cout<< it->second.size() << std::endl;
}

Get the key and values of map elements in a vector of maps from a constant iterator to the vector of maps

I have a vector of maps containing strings .,i.e,
vector< map <string,string> > vectorOfMaps;
vector< map <string,string> >::const_iterator itr =vectorOfMaps.begin();
vectorOfMaps is filled in another function and the caller function can access only the const_iterator itr.
How do i access the key and its respective value of each map element in the vectorOfMaps?
Any help appreciated:)
EDIT: Got my solution.
map<string,string> myMap = (*itrVectorOfMaps);
while(loop till the end element)
{
for(map<string,string>::iterator itM = myMap.begin();
itM != myMap.end(); itM++)
{
cout<<"Key="<<itM->first<<" => Value="<<itM->second<<endl;
}
itrVectorOfMaps++;
myMap=(*itrVectorOfMaps);
}
You can use the first and second keywords to access the map elements as you're iterating over the vector of maps.
for(auto const& currentMap : vectorOfMaps) // Loop over all the maps
{
for(auto const& element : currentMap) // Loop over elements of current map
{
std::string const& key = element.first;
std::string const& value = element.second;
}
}
Your solution is bad because you make multiple copies of maps, first one just before the loop and then inside the loop. Consider this shorter and faster version:
for (auto const& el: *itrVectorOfMaps)
cout << "Key=" << el.first << " => Value=" << el.second << endl;

std::map of iterators to itself

My goal is to map elements of a type to other elements of the same type. Suppose they are size_t for simplicity.
std::map<size_t, size_t> myMapping;
This would do it, but if I want to follow a bunch of such links (they are all the same map), each step is a log(n) lookup.
size_t k = /*whatever*/;
myMapping[myMapping[myMapping[k]]]; //3 * log(n)
I want to make use of the fact that map iterators remain valid and have a map that maps size_t to iterators into itself.
typedef /*myMapTemplate*/::iterator map_iter;
std::map<size_t, map_iter> myMapping;
size_t k = /*whatever*/
map_iter entryPoint = myMapping.find(k);
entryPoint->second->second->first; //log(n) + 2 constant time operations
How would I write this type?
I know copying would keep iterators to old map and plan to take care of this myself.
I understand your question that you want map: key->map<key,>::iterator
So, here it is, a struct with map iterator as value:
template <
template <class K, class V, class C, class A> class mapImpl,
class K,
class V,
class C=std::less<K>,
class A=std::allocator<std::pair<const K, V> >
>
class value_with_iterator {
public:
typedef typename mapImpl<const K,value_with_iterator,C,A>::iterator value_type;
value_type value;
};
Map defined with using struct above:
typedef std::map<size_t, value_with_iterator <std::map, size_t, size_t> > map_size_t_to_itself;
Some insert method - to link key with itself:
map_size_t_to_itself::iterator insert(map_size_t_to_itself& mapRef, size_t value)
{
map_size_t_to_itself::value_type v(value, map_size_t_to_itself::mapped_type());
std::pair<map_size_t_to_itself::iterator, bool> res = mapRef.insert(v);
if (res.second)
res.first->second.value = res.first;
return res.first;
}
And simple test:
int main() {
map_size_t_to_itself mapObj;
map_size_t_to_itself::iterator i1 = insert(mapObj, 1);
map_size_t_to_itself::iterator i2 = insert(mapObj, 1);
map_size_t_to_itself::iterator i3 = insert(mapObj, 2);
std::cout << i1->first << ": " << i1->second.value->first << std::endl;
std::cout << i2->first << ": " << i2->second.value->first << std::endl;
std::cout << i3->first << ": " << i3->second.value->first << std::endl;
}
with OUTPUT:
1: 1
1: 1
2: 2
Full link: http://ideone.com/gnEhw
If I understood your problem correctly, I think I would keep my elements in a vector and use a vector of indices into the first vector for the kind of indirection you want. If you also need ordered access you can always throw in a map to the elements of the first vector.