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;
}