Home > Software engineering >  Aggregate values of same key in std::multimap and store in std::map
Aggregate values of same key in std::multimap and store in std::map

Time:03-19

I essentially want to group the elements of the multimap by key, and obtain the new data structure as a map.

the multimap:

std::multimap<std::string,std::vector<int>> multiMap;
 
    VecA VecB
ABC  10  30
ABC  10  30
DEF  20  20

the output required:

std::map<std::string,std::vector<int>> map;

   VecA VecB
ABC 20  60
DEF 20  20

The following code works for a std::multimap<std::string,int>

std::vector<std::string> a = {ABC,ABC,DEF,GHI};
std::vector<int> b = {10,20,30,40};
    
std::multimap<std::string,int> multiMap;

for (int i = 0; i < a.size(); i  )
{
  multiMap.insert(std::pair<std::string,int >(a[i], b[i]));
}

std::map<std::string,int> map;

std::for_each
(
multiMap.begin(),
multiMap.end(),
[&map] (auto const & i) 
 {
   map[i.first]  = i.second;
 }
);

I am unable to change the code in line 19 of the above block (i.e. in the lambda function) to extend in the case of std::multimap<std::string,std::vector<int>> to std::map<std::string,std::vector<int>>

CodePudding user response:

If you want use Arithmetic operators

Use valarray

Demo: https://wandbox.org/permlink/SAnHNKNZ0UufqZsN

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <valarray>
#include <numeric>

int main()
{

    using key_type = std::valarray<int>;
    key_type b = {10,20,30,40};
    
    auto containerToStr = [](const auto& cont)
    {
       return std::accumulate(std::begin(cont), std::end(cont), std::string{}, [](const auto& str, const auto& val){
           return str   " "   std::to_string(val);
       });
    };

    
    std::multimap<std::string,key_type> multiMap;
    std::vector<std::string> a = {"ABC","ABC","DEF","GHI"};
    for (size_t i = 0; i < a.size(); i  )
    {
        multiMap.insert(std::pair<std::string,key_type >(a[i], b));
    }

    std::cout << "Before sum" << std::endl;
    for (const auto& p : multiMap)
        std::cout << p.first << " " << containerToStr(p.second) << std::endl;
    std::cout << std::endl;
    
    std::map<std::string,key_type> map;


    std::for_each( multiMap.begin(), multiMap.end(), [&map] (auto const & i) 
        {
            //  map[i.first]  = i.second; // caution  map[i.first] create an empty key_type 
            if ( map.count(i.first) > 0)
            {
                map.at(i.first)  = i.second;
            }
            else
            {
                map.insert({i.first, i.second});
            }
        }
    );

    std::cout << "After sum" << std::endl;
    for (const auto& p : map)
        std::cout << p.first << " " << containerToStr(p.second) << std::endl;
}

If you want use std::vector

Define your sum function.

Demo: https://wandbox.org/permlink/FteFkLfwQh0P4wzp

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <numeric>

int main()
{

    using key_type = std::vector<int>;
    key_type b = {10,20,30,40};
    
    auto containerToStr = [](const auto& cont)
    {
       return std::accumulate(std::begin(cont), std::end(cont), std::string{}, [](const auto& str, const auto& val){
           return str   " "   std::to_string(val);
       });
    };

    
    std::multimap<std::string,key_type> multiMap;
    std::vector<std::string> a = {"ABC","ABC","DEF","GHI"};
    for (size_t i = 0; i < a.size(); i  )
    {
        multiMap.insert(std::pair<std::string,key_type >(a[i], b));
    }

    std::cout << "Before sum" << std::endl;
    for (const auto& p : multiMap)
        std::cout << p.first << " " << containerToStr(p.second) << std::endl;
    std::cout << std::endl;
    
    std::map<std::string,key_type> map;

    // Warning : naive function, to rework
    auto your_sum = [](const auto& cont1, const auto& cont2)
    {
        key_type result;
        const auto smaller = std::min(cont1.size(), cont2.size());
        for ( size_t i = 0 ; i < smaller; i  )
        {
              result.push_back(cont1[i] cont2[i]);  
        }
        return result;
    };

    std::for_each( multiMap.begin(), multiMap.end(), [&map,&your_sum] (auto const & i) 
        {
            //  map[i.first]  = i.second; // caution  map[i.first] create an empty key_type 
            if ( map.count(i.first) > 0)
            {
                map.at(i.first) = your_sum(i.second, map.at(i.first));
            }
            else
            {
                map.insert({i.first, i.second});
            }
        }
    );

    std::cout << "After sum" << std::endl;
    for (const auto& p : map)
        std::cout << p.first << " " << containerToStr(p.second) << std::endl;
}
  • Related