How to iterate through a map of vectors while deleting? - c++

I have a map of vectors in C++. For each vector, I'd like to delete entries that meet a certain condition. If a vector ends up empty, I'd like to delete it from the map. I know deletion can mess up iterators, and doubly iterating makes this even more confusing for me. What's the best way to accomplish this?

The standard mutating container loop:
for (auto it = m.begin(); it != m.end(); )
{
// work
if (/* need to delete */) // e.g "if (it->second.empty())"
{
it = m.erase(it);
}
else
{
++it;
}
}

Here is a demonstrative program that shows how it can be done
#include <iostream>
#include <map>
#include <vector>
int main()
{
std::map<int, std::vector<int>> m =
{
{ 1, { 1, 2 } },
{ 2, { 2 } },
{ 3, { 3, 4 } },
{ 4, { 4 } }
};
for ( const auto &p : m )
{
std::cout << p.first << ": ";
for ( int x : p.second ) std::cout << x << ' ';
std::cout << std::endl;
}
for ( auto it = m.begin(); it != m.end(); )
{
it->second.erase( it->second.begin() );
if ( it->second.empty() ) it = m.erase( it );
else ++it;
}
std::cout << std::endl;
for ( const auto &p : m )
{
std::cout << p.first << ": ";
for ( int x : p.second ) std::cout << x << ' ';
std::cout << std::endl;
}
return 0;
}
The program output is
1: 1 2
2: 2
3: 3 4
4: 4
1: 2
3: 4

Related

Display message when the vector is empty

I would like to know how to display a message when a vector is empty. I know what is required but I don't know how to must be structured.
void displaypoints(const vector<int>& vec) {
cout << "[";
for (const auto& i : vec) {
cout << i << ' ';
}
cout << "]" << endl;
};
int main() {
vector <int> myvec {};
vector <int> newvec {1,2,3,4,5};
cout << "myvec";
displaypoints(myvec);
cout << "newvec";
displaypoints(newvec);
if (newvec.at(0) == 1) {
auto iq = find(newvec.begin(), newvec.end(), 1);
if (iq != newvec.end()) {
newvec.erase(iq);
}
if (newvec.begin(), newvec.end(), 2) {
auto ik = find(newvec.begin(), newvec.end(), 2);
if (ik!= newvec.end()) {
myvec.push_back(*ik);
newvec.erase(ik);
}
else if (newvec.begin(), newvec.end(), 3) {
auto ik = find(newvec.begin(), newvec.end(), 3);
if (ik!= newvec.end()) {
myvec.push_back(*ik);
newvec.erase(ik);
}
}
}
}
if (newvec.at(0) == 5) {
auto ik = find(newvec.begin(), newvec.end(), 5);
if (ik!= newvec.end()) {
myvec.push_back(*ik);
newvec.erase(ik);
}
}
displaypoints(newvec);
displaypoints(myvec);
}
The code above looks for the number 1, erases it then moves 2 to the myvec vector. If there is no 2 then it moves 3 because of the position 0 I have added. There is also another if statement that moves 5 if it is placed at position 0. What I want is another if statement to print a message if there is nothing in the newvec vector.
void displaypoints(vector<int> & vec){
if(vec.empty()){
cout<<"Vector Empty \n";
}
else {
//do your operations
}
}
whatever Ide you are using try first clean build and then build all and run the code it will work.
#include <algorithm>
#include <iostream>
#include <vector>
void
display_points(const std::vector<int>& v)
{
if (v.empty()) {
std::cout << "Empty vector.\n";
} else {
std::cout << "[ ";
for (const auto& i : v) {
std::cout << i << ' ';
}
std::cout << "]\n";
}
}
int
main()
{
std::vector<int> myvec;
std::vector<int> newvec{ 1, 2, 3, 4, 5 };
std::cout << "myvec: ";
display_points(myvec);
std::cout << "newvec:";
display_points(newvec);
int i = 1;
while (newvec.size() > 0) {
auto it = std::find(newvec.begin(), newvec.end(), i);
if (it != newvec.end()) {
myvec.push_back(*it);
newvec.erase(it);
}
++i;
}
std::cout << "myvec: ";
display_points(myvec);
std::cout << "newvec:";
display_points(newvec);
}

How to traverse a map of the form pair<int,pair<int,int>> with a iterator

I defined map like
map <int,pair<int,int>> hmap;
If there is a pair(2,pair(3,4)) how to get 2 3 4 values, itr->first, itr->second not working
If there is a pair(2,pair(3,4)) how to get 2 3 4 values [from an iterator itr to map<int,pair<int, int>>]
I suppose
itr->first // 2
itr->second.first // 3
itr->second.second // 4
Here is a demonstrative program with using iterators and the range-based for statement.
#include <iostream>
#include <map>
int main()
{
std::map<int, std::pair<int, int>> hmap{ { 1, { 2, 3 } }, { 2, { 3, 4 } } };
for (auto it = hmap.begin(); it != hmap.end(); ++it)
{
std::cout << "{ " << it->first
<< ", { " << it->second.first
<< ", " << it->second.second
<< " } }\n";
}
std::cout << std::endl;
for (const auto &p : hmap)
{
std::cout << "{ " << p.first
<< ", { " << p.second.first
<< ", " << p.second.second
<< " } }\n";
}
std::cout << std::endl;
}
Its output is
{ 1, { 2, 3 } }
{ 2, { 3, 4 } }
{ 1, { 2, 3 } }
{ 2, { 3, 4 } }

Choosing a for loop based on if condition

Condition based for loop selection.
if(valid)
for (std::multimap<int,int>::reverse_iterator rit=id_count.rbegin(); mcount<10 && rit!=id_count.rend();++rit)
else
for (std::multimap<int,int>::iterator rit=id_match.begin(); mcount<10 && rit!=id_match.end();++rit)
{
//this is common for both for loop
}
how to achieve this in C++?
You have no choice but putting the common part in a function, very roughly like this:
void somefunction(...)
{
//this is common for both for loops
}
if (valid)
{
for (std::multimap<int,int>::reverse_iterator rit=id_count.rbegin(); mcount<10 && rit!=id_count.rend();++rit)
somefunctiuon(...);
}
else
{
for (std::multimap<int,int>::iterator rit=id_match.begin(); mcount<10 && rit!=id_match.end();++rit)
somefunctiuon(...);
}
This is arguably most useful as an illustration that it's not worth combining the loop logic, though it does work. Provided here for interest value...
#include <iostream>
#include <map>
int main()
{
std::multimap<int,int> id_count = { {1,2}, {9, -2}, {1,44}, {2,3}, {3,5}, {7,34} };
for (int valid = 0; valid < 2; ++valid)
{
std::cout << "valid " << valid << '\n';
int mcount = 0;
for (std::multimap<int,int>::iterator it = valid ? id_count.rbegin().base()
: id_count.begin();
mcount<10 && (valid ? it--!=id_count.begin() : it!=id_count.end());
(valid ? it : ++it), ++mcount)
{
std::cout << "[mcount " << mcount << "] "
<< it->first << ',' << it->second << '\n';
}
std::cout << '\n';
}
}
You can create a template function:
#include <map>
#include <iostream>
template<typename I> void func(I begin, I end) {
int mcount = 0;
for (I it = begin; mcount < 10 && it != end; ++it) {
++mcount;
std::cout << "[mcount " << mcount << "] "
<< it->first << ',' << it->second << '\n';
}
}
int main() {
std::multimap<int,int> id_count = { {1,2}, {9, -2}, {1,44}, {2,3}, {3,5}, {7,34} };
for (int valid = 0; valid < 2; ++valid) {
std::cout << "valid " << valid << '\n';
if (valid) {
func(id_count.rbegin(), id_count.rend());
} else {
func(id_count.begin(), id_count.end());
}
std::cout << '\n';
}
}
But IMHO this solution is a bit complicated, so consider other ways (like placing the loop body in a function).
You can try "#if valid", like:
#if 0
for(i=1;i<10;++i)
#else
for(i=2;i<9;++i)
#endif
{
cout << i << endl;
}
In C++14 you also have an option to use generic lambdas:
auto common_code = [/* Capture state if needed */] ( auto& Iter )
{
// Your common code
};
if ( valid )
for ( std::multimap<int, int>::reverse_iterator rit = id_count.rbegin(); mcount < 10 && rit != id_count.rend(); ++rit )
common_code( rit );
else
for ( std::multimap<int, int>::iterator rit = id_match.begin(); mcount < 10 && rit != id_match.end(); ++rit )
common_code( rit );

how to subtract std::map elements from one to other and update it in C++

I am trying to subtract the 1st element of the std::map from every other element of that same std::map. I couldn't find anything about that. Is it possible? for example :
std::map<char,int> bar;
bar['a']=11; //should be deleted from other elements
bar['b']=22;
bar['c']=33;
bar['d']=44;
std::cout << "bar contains:\n";
for (std::map<char,int>::iterator it=bar.begin(); it!=bar.end(); ++it)
{
std::cout <<"key: " <<it->first << " Value=> " << it->second << '\n'; //can i delete here??
//i want to delete value of a from value of b and update the value of b
}
//the new map should be look like as follows
//bar['a']=11; //or may be 0
//bar['b']=11;
//bar['c']=22;
//bar['d']=33;
Any ideas to do it easily with map in c++?
Thanks.
C++11 Solution
You could use std::for_each for this
std::for_each(std::next(bar.begin()), bar.end(), [&bar](std::pair<const char, int>& x){ x.second -= bar.begin()->second; });
For example
#include <algorithm>
#include <iostream>
#include <iterator>
#include <map>
int main()
{
std::map<char,int> bar;
bar['a']=11;
bar['b']=22;
bar['c']=33;
bar['d']=44;
std::for_each(std::next(bar.begin()), bar.end(), [&bar](std::pair<const char, int>& x){ x.second -= bar.begin()->second; });
std::cout << "bar contains:\n";
for (std::map<char,int>::iterator it=bar.begin(); it!=bar.end(); ++it)
{
std::cout << "key: " << it->first << " Value=> " << it->second << '\n';
}
}
Output (working demo)
bar contains:
key: a Value=> 11
key: b Value=> 11
key: c Value=> 22
key: d Value=> 33
And if you want to subtract even the first element from itself, just remove the std::next call and capture the value you want to subtract out, since you're going to modify the first map entry.
auto const sub = bar.begin()->second;
std::for_each(bar.begin(), bar.end(), [&sub](std::pair<const char, int>& x){ x.second -= sub; });
C++03 Solution
To subtract the first element from everything except the first element itself
int value = bar.begin()->second;
std::map<char, int>::iterator it = bar.begin();
std::advance(it, 1);
for (; it != bar.end(); ++it)
{
it->second -= value;
}
To include the first element
int value = bar.begin()->second;
for (std::map<char, int>::iterator it = bar.begin(); it != bar.end(); ++it)
{
it->second -= value;
}
You simply need to loop over the map and subtract the value associated with the "first" key from each element, storing the result back into the same element. One approach to that is shown below:
Live example at http://coliru.stacked-crooked.com/a/1bc650592027f5f3
#include <iostream>
#include <map>
int main() {
// Set up the problem...
std::map<char, int> foo;
foo['a'] = 11;
foo['b'] = 22;
foo['c'] = 33;
foo['d'] = 44;
// Obtain the value of the 'a' key...
const int value = foo['a'];
// Subtract that value from each element...
for (auto& element : foo) {
element.second -= value;
}
// Output the map to verify the result...
for (auto& element : foo) {
std::cout << element.first << ": " << element.second << "\n";
}
return 0;
}
Note that if you loop over the entire map, you need to store the initial value of foo[a], since you'll zero it during the iterative subtraction. You can avoid this by using iterators and skipping over the first element using e.g. std::next(foo.begin()). Other answers demonstrate this technique, so I won't duplicate it here.
You can use standard algorithm std::for_each declared in header <algorithm>
If your compiler supports C++ 2014 then the code can look like
#include <iostream>
#include <map>
#include <algorithm>
#include <iterator>
int main()
{
std::map<char, int> bar;
bar['a'] = 11;
bar['b'] = 22;
bar['c'] = 33;
bar['d'] = 44;
for ( const auto &p : bar )
{
std::cout << "{ " << p.first << ", " << p.second << " } ";
}
std::cout << std::endl;
if ( !bar.empty() )
{
std::for_each( std::next( bar.begin() ), bar.end(),
[value = ( *bar.begin() ).second] ( auto &p ) { p.second -= value; } );
}
for ( const auto &p : bar )
{
std::cout << "{ " << p.first << ", " << p.second << " } ";
}
std::cout << std::endl;
}
The program output is
{ a, 11 } { b, 22 } { c, 33 } { d, 44 }
{ a, 11 } { b, 11 } { c, 22 } { d, 33 }
If your compiler supports only C++ 2011 then the main loop in the program can look like
if ( !bar.empty() )
{
auto value = ( *bar.begin() ).second;
std::for_each( std::next( bar.begin() ), bar.end(),
[value] ( std::pair<const char, int> &p ) { p.second -= value; } );
}
The same can be done using for example the range based for loop
#include <iostream>
#include <map>
int main()
{
std::map<char, int> bar;
bar['a'] = 11;
bar['b'] = 22;
bar['c'] = 33;
bar['d'] = 44;
for ( const auto &p : bar )
{
std::cout << "{ " << p.first << ", " << p.second << " } ";
}
std::cout << std::endl;
if ( !bar.empty() )
{
auto value = ( *bar.begin() ).second;
bool first = true;
for ( auto &p : bar )
{
if ( first ) first = !first;
else p.second -= value;
}
}
for ( const auto &p : bar )
{
std::cout << "{ " << p.first << ", " << p.second << " } ";
}
std::cout << std::endl;
}
Also if the element by which all other elements should be decreased is not necessary the first element of the map then you can use the following approach
#include <iostream>
#include <map>
#include <algorithm>
#include <iterator>
int main()
{
std::map<char, int> bar;
bar['a'] = 11;
bar['b'] = 22;
bar['c'] = 33;
bar['d'] = 44;
for ( const auto &p : bar )
{
std::cout << "{ " << p.first << ", " << p.second << " } ";
}
std::cout << std::endl;
if ( !bar.empty() )
{
// the initializer can be any element not only the first one
const auto &value = *bar.begin();
for ( auto &p : bar )
{
if ( p.first != value.first ) p.second -= value.second;
}
}
for ( const auto &p : bar )
{
std::cout << "{ " << p.first << ", " << p.second << " } ";
}
std::cout << std::endl;
}
int value = bar.begin()->second;
for(std::map<char,int>::reverse_iterator it=bar.rbegin(); it != bar.rend(); it++) {
it->second -= bar.begin()->second;
}
bar.begin()->second = value;

My range for loop doesn't work

I have to print out the size of the vector and all the contents inside it. But my for loop doesnt iterate, it doesn't go up by one but instead stays at the value 0 for the whole loop.
#include "stdafx.h"
#include <string.h>
#include <string>
#include <iostream>
#include <cctype>
#include <vector>
#include <list>
using std::string;
using std::vector;
vector<int> v2(10);
for( auto i : v2)
{
if( i == 0 )
{
std::cout << v2.size() << std::endl;
}
std::cout << "Element value " << (i) << " is " << v2[i] << std::endl;
}
So I only want to print the size once, at the start. Then print out each element value which I know will be 0 by default. But it just prints out "Element value 0 is 0" 9 times.
If you want at first to print out the size of the vector then place this output statement before the range based for statement
std::vector<int> v2(10);
std::cout << v2.size() << std::endl;
size_t i = 0;
for ( auto x : v2 )
{
std::cout << "Element value " << i++ << " is " << x << std::endl;
}
But if you are using a count then it would be better to use the ordinary for statement
std::vector<int> v2(10);
std::cout << v2.size() << std::endl;
for ( std::vector<int>::size_type i = 0; i < v2.size(); i++ )
{
std::cout << "Element value " << i << " is " << v2[i] << std::endl;
}
Your question indicates that you want to treat the first element differently. This does not work with range-based for loops out of the box. You have two options:
Use an extra variable to remember whether the first iteration was made.
Use a traditional loop, using an index variable or an iterator.
Example for 1:
bool first_iteration = true;
for( auto i : v2)
{
if (first_iteration)
{
std::cout << v2.size() << std::endl;
first_iteration = false;
}
// ...
}
Example for 2:
for (auto iter = v2.begin(); iter != v2.end(); ++iter)
{
if (iter == v2.begin())
{
std::cout << v2.size() << std::endl;
}
// ...
}