Check if map in C++ contains all the keys from another map answers my question but I'm not sure how we iterate through two maps at the same time.
I know how to iterate through one as shown:
typedef std::map<QString, PropertyData> TagData;
TagData original = readFileToMap("FoxHud.bak");
for (TagData::const_iterator tagIterator = original.begin(); tagIterator != original.end(); tagIterator++) {
}
Try this way:
// As std::map keys are sorted, we can do:
typedef std::map<string, int> TagData;
TagData map1;
TagData map2;
...
TagData::const_iterator map1It = map1.begin();
TagData::const_iterator map2It = map2.begin();
bool ok = true;
std::size_t cnt = 0;
while (map2It != map2.end() && map1It != map1.end()) {
if (map1It->first != map2It->first) {
map1It++;
} else {
map2It++;
cnt++;
}
}
if (cnt != map2.size()) ok = false;
cout << "OK = " << ok << endl;
This should work with maps that are not the same size, as well.
If you want to iterate the 2 maps simultaneously, you can do this:
if (map1.size() != map2.size())
; // problem
else
{
for (map<X,Y>::const_iterator it1 = map1.begin(),
it2 = map2.begin();
it1 != map1.end() && it2 != map2.end();
++it1 , ++it2)
{
// ...
}
}
Now if you want to iterate through the 2 maps at different "speeds", then a while loop to condition the increments of it1 and it2 independently would then be more appropriate. See Golgauth's answer for an example.
Related
I'm trying to remove elements that have the same key and value in a multimap. This is my code for now. After deleting the element, I get exception.
multimap<string, CStudent> m_StudentMap;
void removeDuplicates() {
for (auto it1 = m_StudentMap.begin(); it1 != --m_StudentMap.end(); it1++) {
for (auto it2 = next(it1, 1); it2 != m_StudentMap.end(); it2++) {
if (it1->first == it2->first) {
if (it1->second == it2->second) {
m_StudentMap.erase(it2);
}
}
}
}
}
You were nearly right, but the trick with erasing elements in maps while iterating is to capture the new iterator returned by erase. I've also generalised the function so it can be used on an argument rather than being limited to m_StudentMap, and stopped the inner loop as soon as the keys diverge.
template <typename K, typename V>
void removeDuplicates(std::multimap<K, V>& mmap)
{
if (mmap.size() < 2) return;
for (auto it = mmap.begin(); it != prev(mmap.end()); ++it)
for (auto it2 = next(it); it2 != mmap.end() && it2->first == it->first; )
if (it->second == it2->second)
it2 = mmap.erase(it2);
else
++it2;
}
You can see it run / fork it etc. here.
First of all, I'm using C++98/03
I'm iterating my multimap starting from the second element:
multimap<pair<string, string>, pair<string, int> >::iterator it = paths.begin();
it++;
I have a conditional statement: if first element of first pair in current iterator is equal to the first element of first pair in a previous iterator, then do something, eg. print these elements.
for(; it != paths.end(); it++) {
if((*it).first.first == (*it--).first.first ) {
it++;
cout << (*it).first.first << " ";
cout << (*it--).first.first << endl;
it++;
}
else {
it++;
}
}
My question is how can I use a copy of an iterator instead of incrementing it back after every (*it--)?
Create an utility similar to C++11's std::prev:
#include <algorithm>
template <class T>
T prev(T it)
{
std::advance(it, -1);
return it;
}
Then use it as follows:
for(; it != paths.end(); it++) {
if((*it).first.first == prev(it)->first.first ) {
cout << (*it).first.first << " ";
cout << prev(it)->first.first << endl;
}
else {
it++;
}
}
Just use another iterator:
typedef multimap<pair<string, string>, pair<string, int> >::iterator iterator;
for( iterator it = paths.begin(); it != paths.end(); ) {
iterator prev = it++;
if( it == paths.end() )
break;
if( prev->first.first == it->first.first ) {
// output here
}
}
Note your code is incorrect, first of all it has UB as == is not sequenced. But even if you use different iterator on the left side, you would get wrong behaviour:
iterator it1 = it;
if((*it1).first.first == (*it--).first.first ) { // not UB anymore, but result is always true as you compare the same element
map <int, map<int, string>> DP;
if( DP.find( ? ) != DP.end() )
{
// have found
}
How to fill in (). It seem like two dimension. I know how to deal with one dimension, for example:
map<int, string> DP;
if( DP.find(1) != DP.end() )
{
// have found
}
But I don't know how to deal with two dimension.
One dimension at a time:
auto it1 = DP.find(1);
if (it1 != DP.end()) {
auto it2 = it1->find(2);
if (it2 != it1->end()) {
// found: it2->second
}
}
I think Kerrek SB`s codes exists a little problem. The way of visiting second(inner) dimension should be like this:
auto OuterIter = DP.find(1);
if (OuterIter != DP.end())
{
auto InnerMap = OuterIter->second;
auto InnerIter = InnerMap.find(0);
if (InnerIter != InnerMap.end())
{
// found the second(inner) dimension element
}
}
And you can think about chtz`s advise: You may also consider directly using std::map, std::string>
How to iterate through a std::map<string,int> and std::vector<int> using single for loop ?
I have seen this questions but could not solve my problem.
I am trying like this
map<string,int> data;
data["Shravan"] = 1;
data["Mama"] = 2;
data["Sa1"] = 3;
data["Jhandu"] = 4;
vector<int> values = {1,2,3,4};
for(const auto& it1: data,it2 : values) {
// Do something
}
Edit : I can not go through one by one. Because i am using the key of std::map and value of std::vector in the same function. Which will be called inside for loop.
Both the container of same size.
If you know there's both the same length, use something like:
auto vit = begin(value);
auto mit = begin(data);
for (; vit != end(value); ++mit, ++vit) {
// Use mit and vit
}
How about a do-while? Provided that your containers aren't empty.
auto iv = std::begin(value);
auto id = std::begin(data);
do {
// Use those iterators
} while(++iv != std::end(value) && ++id != std::end(data))
Or use while if you'd like to handle empty containers too.
auto iv = std::begin(value);
auto id = std::begin(data);
while(iv != std::end(value) && id != std::end(data)) {
// Use those iterators
iv++; id++;
}
Consider boost::zip_iterator discussed in this answer https://stackoverflow.com/a/8513803/2210478
You can iterate over both the map and the vector and make sure to check the iterators against the end of the corresponding container.
auto map_iter = data.begin();
auto vec_iter = value.begin();
for (; map_iter != data.end() && vec_iter != value.end();
++map_iter, ++vec_iter) {
// Use map_iter and vec_iter
}
I have the following code in a function.
events is a global variable:
map<string, map<string, deque<Event> > > events;
this is my function:
void remove_events(vector<Event> c_events)
{
vector<Event>::iterator it1;
deque<Event>::iterator it2;
for(it1 = c_events.begin(); it1 != c_events.end(); ++it1)
{
it2 = events[it1->device][it1->dev_id].begin();
while(it2 != events[it1->device][it1->dev_id].end())
{
if(*it1 == *it2)
{
it2 = events[it1->device][it1->dev_id].erase(it2);
}
else ++it2;
}
}
}
c_events contains the objects I want to remove from events. However, the objects still remain in events after I tried removing them.
Let me know if you need me to post more code.