read set from map in c++ - c++

It's very silly question but somehow I am not able to solve.
I have map who key is string and value is set and I want to iterate through value and print it for example
std::map<std::string, std::set<std::string>> test_map_set
for (auto it_map = test_map_set["test"].begin(); it_mpa != test_map_set["test"].begin(); it_map ++ )
{
auto it = it_map->second; ===> Here I am getting error that it has no member second
then iterate through set
}
My question is how to iterate through set ?

Indeed std::string has no member second.
Since you have c++11, you can make life a lot easier:
std::map<std::string, std::set<std::string>> test_map_set
for (std::string& set_element : test_map_set["test"])
{
}
For deleting:
auto& test = test_map_set["test"];
for (auto it = test.begin(); it!= test.end();)
{
if (it->length()==5)
it = test.erase(it);
else
++it;
}
This would delete all strings of 5 characters

Related

Getting a substr from a std::variant<std::string, std::vector<std::string>>> in C++

So I've got a map with a string key and either a string or vector value. I want to cycle through all the string values (whether they're found in a vector or they can be directly checked) in the map and check if they match a given string (it's irrelevant what the string is). If that string matches completely or partly, I will put the map that the string was found in inside a vector.
The issue I'm having is that even though I'm separating strings from vectors using an if conditional the substr function thinks I'm dealing with a std::variant<std::string, std::vector<std::string>>> and therefore gives me an error.
The begin functions in the else functions also tell me that variant doesn't have a member called "begin" because of this reason. I'm totally lost, any help would be great.
for (std::unordered_map<std::string,
std::variant<std::string,
std::vector<std::string>>>::iterator h = MyMap.begin();
h != MyMap.end();
h++) {
if (typeid(h->second) == typeid(std::string)) {
std::string MapValueString = h->second.substr(0, TextCtrlValue.length());
if (MapValueString == TextCtrlValue) {
RightSearchResultsVector.insert(RightSearchResultsVector.end(), Maps.begin(), Maps.end());
}
}
else {
for (std::vector<std::string>::iterator f = h->second.begin(); f != h->second.end(); f++) {
// Go through vector and find matching/semi matching strings
}
}
}
Here's how to tell what type a variant holds
std::string* pstr = std::get_if<std::string>(&h->second);
if (pstr != nullptr)
{
// do stuff with string
}
else
{
std::vector<std::string>& vec = std::get<std::vector<std::string>>(h->second);
// do stuff with vector
}
BTW you can simplify this monstrosity
for (std::unordered_map<std::string,
std::variant<std::string,
std::vector<std::string>>>::iterator h = MyMap.begin();
by writing
for (auto h = MyMap.begin();
Judicious use of auto can greatly improve the readability of your code.

Get the previous or next item in a map from a for loop

I'm making a calculator that can accept more than one operator at once (e.g. 5x5x5). I have a map that contains the positions of the operators, and what type they are (x/+-). I also have a for loop for (auto const& [key, val] : oper_map) which I got from this post.
In order to get the left and right numbers, I need to know where the left and right operators are. I've attempted to use std::prev and std::next with the key like this:
int loper_pos = -1;
int roper_pos = 0;
double lnum;
double rnum;
char loper;
char roper;
//map defined elsewhere
for (auto const& [key, val] : oper_map)
{
//loper is left operator while roper is right opeprator
//tracks the position of the loop
int map_pos = std::distance(oper_map.begin(), oper_map.find(key));
if (map_pos == 0) loper_pos = -1;
else
{
loper_pos = std::prev(key);
loper = std::prev(val);
}
if (map_pos == oper_map.size()) roper_pos = oper_map.size() + 1;
else
{
roper_pos = std::next(key);
roper = std::next(val);
}
but I guess it doesn't work since key isn't an iterator? I also can't increment/decrement key or val (or when using the C++11 version in this post), so I guess it doesn't count as an iterator? I don't know iterators confuse me.
This post appears to be what I want but for whatever reason lower_bound() does not work with oper_map; no suitable conversion.
No. key is not an iterator.
for (auto const& [key, val] : oper_map)
key is a const reference to the key in the map. If you want iterators, use iterators:
for (auto it = oper_map.begin(); it != oper_map.end(); ++it) {
auto next = std::next(it);
auto prev = std::prev(it);
}
However, consider that std::map is not a sequential container. If you are interested in the positions of elements in the container, maybe a std::vector< std::pair<Key,MappedValue>> is more handy.

c++ unordered_map iterator on single object

I have a string and an unordered_map of (string, Object). I already have some code in which I am iterating over the map:
for(auto& item : map) {
do_something;
}
I want to modify it to do the part inside the for loop when the string is non-empty and found inside the map else if string is empty do it for all items in the map.
if(!string.empty()){
item = map.find(string);
do_something;
}
else {
for(auto& item : map) {
do_something;
}
}
Can I do this without rewriting the do_something or creating a separate function?
To follow the line of thought you presented in the comments. You can replace the range for loop by a regular for loop over a specific range (defined by iterators). To define it, you'd need something like this:
auto begin = map.begin(), end = map.end(); // The whole map
if(!string.empty())
std::tie(begin, end) = map.equal_range(string);
// constrain range to the single element
for(; begin != end; ++begin) { // loop over it
auto& item = *begin;
// Do something
}
The star of the above is std::unordered_map::equal_range.

Combining multiple maps with vectors into one map

I have a question about combining maps that have vectors as the value section. for instance, I might have the following:
std::map<int, std::vector<Affector*> > affectors;
I want to build this map by combining multiple smaller maps. For instance:
for (auto ch = chList.begin(); ch != chList.end(); ++ch)
{
std::map<int, std::vector<Affector*> > tempAff = ch->getemng()->getAffectorsInOrder();
std::map<int, std::vector<Affector*> > tempAff2 = ch->getpmng()->getAffectorsInOrder()
//I want to append both of these maps to the top level affectors map
}
I can think of the obvious solution which would be
for (auto ch = chList.begin(); ch != chList.end(); ++ch)
{
std::map<int, std::vector<Affector*> > tempAff = ch->getemng()->getAffectorsInOrder();
for (auto aff = tempAff.begin(); aff != tempAff.end(); ++aff)
{
affectors[aff->first].push_back(aff->second);
}
tempAff.clear();
tempAff = ch->getpmng()->getAffectorsInOrder();
for (auto aff = tempAff.begin(); aff != tempAff.end(); ++aff)
{
affectors[aff->first].push_back(aff->second);
}
...
}
This will work, but feels inefficient. I can't use the insertion operation of the map since I need to preserve existing values in the vectors. Is there a better way to combine the maps I'm not thinking of?
Thanks
As mentioned by Richard Corden I think that you really want to be using a std::multimap.
std::multimap<int, Affector*> affectors;
If you also make tempAff and tempAff2 std::multimaps you can do:
affectors.insert(tempAff.begin(), tempAff.end());
affectors.insert(tempAff2.begin(), tempAff2.end());

How to check if my iterator stands on nothing

i'm using a multimap stl, i iterate my map and i did'nt find the object i wanted inside the map, now i want to check if my iterator holds the thing i wanted or not and i'm having difficulties with it because it's not null or something. thanx!
If it doesn't find the thing you want then it should equal the iterator returned by the end() method of the container.
So:
iterator it = container.find(something);
if (it == container.end())
{
//not found
return;
}
//else found
Why are you iterating over your map to find something, you should go like ChrisW to find a key in your map...
Mmm, are you trying to find the value in your map and not the key? Then you should do:
map<int, string> myMap;
myMap[1] = "one"; myMap[2] = "two"; // etc.
// Now let's search for the "two" value
map<int, string>::iterator it;
for( it = myMap.begin(); it != myMap.end(); ++ it ) {
if ( it->second == "two" ) {
// we found it, it's over!!! (you could also deal with the founded value here)
break;
}
}
// now we test if we found it
if ( it != myMap.end() ) {
// you also could put some code to deal with the value you founded here,
// the value is in "it->second" and the key is in "it->first"
}