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

2.3k views Asked by At

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.

4

There are 4 answers

5
Cory Kramer On

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;
}
3
Andrew On

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.

2
Vlad from Moscow On

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;
}    
2
john zhao On
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;