C++ How to create a map from two other maps - c++

How to create map MyMap3 as:
std::map< vector<std::pair<int, int>>, int > MyMap3
Example:
MyMap3[0] = ((1,3) , (1,5), 7 ) // 5 = 4 + 3
MyMap3[1] = ( (2,1) , (2,4), 6 ) // 6 = 1 + 5
Where the key = (vector of pairs) extract from 'MyMap1',
and the value = the sum of the pairs' values in 'MyMap2'.
I also don't care about the pair order, (2,4) is the same as (4,2)
std::map <int, vector<pair<int, int>> > MyMap1;
std::map< std::pair< int, int>, int> MyMap2;
Here is an Example:
MyMap1[0] = (0, (1,3) , (1,5) )
MyMap1[1] = (1, (2,1) , (2,4) )
MyMap2[0] = ( (1,3) , 4 )
MyMap2[1] = ( (1,5) , 3 )
MyMap2[2] = ( (2,1) , 1 )
MyMap2[3] = ( (4,2) , 5 )
I don't know how to do that, and this is my try:
std::map <int, vector<pair<int, int>> > ::iterator it1 = MyMap1.begin();
std::map<std::pair< int, int>, int> ::iterator it2 = MyMap2.begin();
// std::map< vector<pair<int, int> >, int> MyMap3;
std::map< pair<int, int> , int> MyMap3;
int i = 0;
while (it1 != MyMap1.end())
{
vector< pair<int, int> > temp = MyMap1[i];
vector< pair<int, int> > ::iterator it3 = temp.begin();
while (it3 != temp.end())
{
int a = it2->first.first;
int b = it2->first.second;
while (it2 != MyMap2.end())
{
if (it3 == MyMap2.find(std::make_pair(a, b))
MyMap3[std::make_pair(a, b)] += it2->second;
else
++it2;
}
++it3;
++i;
}
++it1;
}
I have syntax error in:
if (it3 == MyMap2.find(make_pair(a, b)))
MyMap3[std::make_pair(a, b)] += it2->second;

Your question is confuse, i decipher you want for each key in map1 to sum the value of each pair in the vector found in the map2 to a single value, and store the result with the map1 key. Not really what your code do…
Example result : http://coliru.stacked-crooked.com/a/a4d77c77fa6896c1
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <utility>
using Map1 = std::map< int, std::vector<std::pair<int,int>>>;
using Map2 = std::map< std::pair<int,int>, int >;
using Map3 = std::map< int, int >;
Map3 foo( Map1 const & m1, Map2 const & m2 ) {
auto m2end = m2.end(); // a constant call is move outside the loop
Map3 result;
for( auto & v1 : m1 ) { // each entry in m1 is made of the key as first and the value as second
for( auto & p1 : v1.second ) { // iterate over the vector of pair
auto v2it = m2.find( p1 ); // search for the pair
if ( v2it != m2end ) {
result[v1.first] += v2it->second; // if the pair was found, add the value for it to the result, using the map1 key as key
}
}
}
return result;
}
template<typename T,typename S>
std::ostream& operator<<(std::ostream& os, const std::pair<T,S>& pair )
{
os << "{ " << pair.first << ", " << pair.second << " }";
return os;
}
template<typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& vec)
{
os << "( ";
for (auto& el : vec)
{
os << el << ", ";
}
os << " )";
return os;
}
template<typename T,typename S>
std::ostream& operator<<(std::ostream& os, const std::map<T,S>& map)
{
for (auto& el : map)
{
os << el.first << " : " << el.second << "\n";
}
return os;
}
int main()
{
Map1 m1 { { 0, { {1,3}, {1,5}} }, { 1, { {2,1}, {2,4}} }, };
Map2 m2 { { {1,3}, 4 }, { {1,5}, 3 }, { {2,1}, 1 }, { {2,4}, 5 }, };
auto m3 = foo( m1, m2);
std::cout << "m1 :\n" << m1 << std::endl;
std::cout << "m2 :\n" << m2 << std::endl;
std::cout << "m3 :\n" << m3 << std::endl;
}

Related

Is there any way to sort set of pair of int and pair by greater int and smaller pair in c++?

I have a set<int, pair<int, int> > ms that I want to sort it by greater int and smaller pair<int, int>. For example, if these are the data in my set:
<10, pair<100, 120> >
<20, pair<45, 60> >
<20, pair<50, 10> >
I want it to be this after sorting operation:
<20, pair<45, 60> >
<20, pair<50, 10>
<10, pair<100, 120> >
I know I can insert in set in descending order by std::greater but I don't know how to combine descending and ascending!
Pass a custom compare operator to std::sort.
#include <iostream>
#include <vector>
#include <utility>
#include <algorithm>
int main() {
std::vector<std::pair<int, std::pair<int, int>>> v = {
std::make_pair(10, std::make_pair(100, 120)),
std::make_pair(20, std::make_pair(45, 60)),
std::make_pair(20, std::make_pair(50, 10)),
};
std::sort(v.begin(), v.end(), [](const auto &lhs, const auto &rhs) -> bool {
if (std::get<0>(lhs) > std::get<0>(rhs))
return true;
else if (std::get<0>(lhs) < std::get<0>(rhs))
return false;
else
return std::get<1>(lhs) < std::get<1>(rhs);
});
for (const auto &e : v) {
std::cout << e.first << " " << e.second.first << " " << e.second.second;
std::cout << "\n";
}
}
https://repl.it/repls/ComfortableAfraidKernelmode

Insert with pair vector

Is is possible to use the insert function for a vector but make a pair just like we can do with push_back?
void insert(std::vector<int, std::string>& cont, int value)
{
std::vector<int>::iterator it = std::lower_bound(
cont.begin(),
cont.end(),
value,
std::less<int>()
); // find proper position in descending order
cont.insert((it, std::make_pair(value,""))); // insert before iterator it
}
std::vector<int,std::string> is not allowed, you could change this to std::vector<std::pair<int,std::string>>
furthermore
std::vector<int>::iterator it = std::lower_bound(cont.begin(), cont.end(), value, std::less<int>());
should be changed to compare pairs and return std::vector<std::pair<int,std::string>>::iterator
The function can be written the foollowing way
#include <iostream>
#include <vector>
#include <utility>
#include <algorithm>
#include <string>
std::vector<std::pair<int, std::string>>::iterator
insert( std::vector<std::pair<int, std::string>> &v, int value, bool before = true )
{
std::vector<std::pair<int, std::string>>::iterator it;
std::pair<int, std::string> pair( value, "" );
if ( before )
{
it = std::lower_bound( v.begin(), v.end(), pair );
}
else
{
it = std::upper_bound( v.begin(), v.end(), pair );
}
return v.insert( it, pair );
}
int main()
{
std::vector<std::pair<int, std::string>> v { { 1, "A" }, { 2, "B" } };
for ( const auto &p : v )
{
std::cout << p.first << " \"" << p.second << "\"" << std::endl;
}
std::cout << std::endl;
insert( v, 1 );
insert( v, 1, false );
insert( v, 2 );
insert( v, 2, false );
for ( const auto &p : v )
{
std::cout << p.first << " \"" << p.second << "\"" << std::endl;
}
std::cout << std::endl;
return 0;
}
The program output is
1 "A"
2 "B"
1 ""
1 ""
1 "A"
2 ""
2 ""
2 "B"
As for me I would declare the function the following way
std::vector<std::pair<int, std::string>>::iterator
insert( std::vector<std::pair<int, std::string>> &v,
const std::vector<std::pair<int, std::string>>::value_type &value,
bool before = true );

Merge two maps, summing values for same keys in C++

I have two std::map<int,int> maps and wish to merge them into a third map like this:
if the same key is found in both maps, create a pair in the third map with the same key and a value which a sum of values from the first and second map, otherwise just copy a pair to the third map.
I suspect it can be done with std::accumulate, but I don't understand it well enough.
Here is an example how to do the task with using std::accumulate
#include <iostream>
#include <map>
#include <numeric>
int main()
{
std::map<int, int> m1 = { { 1, 1 }, { 2, 2 }, { 3, 3 }, { 4, 4 } };
std::map<int, int> m2 = { { 2, 5 }, { 3, 1 }, { 5, 5 } };
for ( const auto &p : m1 )
{
std::cout << "{ " << p.first << ", " << p.second << " } ";
}
std::cout << std::endl;
for ( const auto &p : m2 )
{
std::cout << "{ " << p.first << ", " << p.second << " } ";
}
std::cout << std::endl;
std::map<int, int> m3 = std::accumulate( m1.begin(), m1.end(), std::map<int, int>(),
[]( std::map<int, int> &m, const std::pair<const int, int> &p )
{
return ( m[p.first] +=p.second, m );
} );
m3 = std::accumulate( m2.begin(), m2.end(), m3,
[]( std::map<int, int> &m, const std::pair<const int, int> &p )
{
return ( m[p.first] +=p.second, m );
} );
for ( const auto &p : m3 )
{
std::cout << "{ " << p.first << ", " << p.second << " } ";
}
std::cout << std::endl;
return 0;
}
The output is
{ 1, 1 } { 2, 2 } { 3, 3 } { 4, 4 }
{ 2, 5 } { 3, 1 } { 5, 5 }
{ 1, 1 } { 2, 7 } { 3, 4 } { 4, 4 } { 5, 5 }
In fact only for the second map there is a need to use std::accumulate. The first map can be simply copied or assigned to m3.
For example
std::map<int, int> m3 = m1;
m3 = std::accumulate( m2.begin(), m2.end(), m3,
[]( std::map<int, int> &m, const std::pair<const int, int> &p )
{
return ( m[p.first] +=p.second, m );
} );
An overly generic solution inspired by std::set_union. Unlike the first suggested answer, this should run in O(n) instead of O(n log n).
Edit: it's still O(n log n) because of insertions into the final map.
#include <map>
#include <iostream>
#include <iterator>
#include <algorithm>
template<class InputIterT1, class InputIterT2, class OutputIterT, class Comparator, class Func>
OutputIterT merge_apply(
InputIterT1 first1, InputIterT1 last1,
InputIterT2 first2, InputIterT2 last2,
OutputIterT result, Comparator comp, Func func) {
while (true)
{
if (first1 == last1) return std::copy(first2, last2, result);
if (first2 == last2) return std::copy(first1, last1, result);
if (comp(*first1, *first2) < 0) {
*result = *first1;
++first1;
} else if (comp(*first1, *first2) > 0) {
*result = *first2;
++first2;
} else {
*result = func(*first1, *first2);
++first1;
++first2;
}
++result;
}
}
template<class T>
int compare_first(T a, T b) {
return a.first - b.first;
}
template<class T>
T sum_pairs(T a, T b) {
return std::make_pair(a.first, a.second + b.second);
}
using namespace std;
int main(int argc, char **argv) {
map<int,int> a,b,c;
a[1] = 10;
a[2] = 11;
b[2] = 100;
b[3] = 101;
merge_apply(a.begin(), a.end(), b.begin(), b.end(), inserter(c, c.begin()),
compare_first<pair<int, int> >, sum_pairs<pair<int, int> >);
for (auto item : c)
cout << item.first << " " << item.second << endl;
}
I don't think it will be easy (if not impossible) to find a suitable std::algorithm that serves the purpose.
The easiest way would be to first make a copy of map1 to map_result.
Then iterate through map2 and see if any key already exists in map_result then add the values, else add the key_value pair to map_result.
std::map<int,int> map_result( map1 );
for (auto it=map2.begin(); it!=map2.end(); ++it) {
if ( map_result[it->first] )
map_result[it->first] += it->second;
else
map_result[it->first] = it->second;
}

C++ std::map and std::pair<int, int> as Key

I've the following C++ code:
struct MyStruct
{
int a[2];
int b[2];
};
std::map<std::pair<int, int> , MyStruct*> MyMap;
Now I run this loop on MyMap:
for(std::map<std::pair<int, int> , MyStruct*>::iterator itr = MyMap.begin(); itr != MyMap.end(); ++itr)
{
std::pair<int, int> p (itr->first().second, itr->first().first);
auto i = MyMap.find(p);
if(i != MyMap.end())
{
//do something
}
}
What I'm actually trying to do is forming a pair by swapping the elements of another pair , so for example I have a key pair(12,16) in MyMap and also another key pair(16,12); these two key exists in MyMap and I know for sure. But when I apply the above technique MyMap don't return the value corresponding to the swapped key, what I'm guessing that MyMap.find(p) is matching the pointer of Key; but is there a way so that I can force MyMap.find(p) to match the corresponding value in Key (pair) instead of matching the pointers in Key (pair) ? Or is there anything I'm doing wrong here ?
You have some imprecisions in your code, say, your MyStruct does not have a copy constructor, but contains arrays, itr->first() in your for loop, while first doesn't have a call operator, and others. The following code does what you want:
#include <array>
#include <map>
#include <utility>
#include <memory>
#include <stdexcept>
#include <iostream>
struct MyStruct
{
std::array<int, 2> a;
std::array<int, 2> b;
};
template <class T, class U>
std::pair<U, T> get_reversed_pair(const std::pair<T, U>& p)
{
return std::make_pair(p.second, p.first);
}
int main()
{
std::map<std::pair<int, int>, std::shared_ptr<MyStruct>> m
{
{
{12, 16},
std::make_shared<MyStruct>()
},
{
{16, 12},
std::make_shared<MyStruct>()
}
};
std::size_t count = 1;
for(const auto& p: m)
{
try
{
auto f = m.at(get_reversed_pair(p.first));
f -> a.at(0) = count++;
f -> b.at(0) = count++;
}
catch(std::out_of_range& e)
{
}
}
for(const auto& p: m)
{
std::cout << p.first.first << ' ' << p.first.second << " - ";
std::cout << p.second -> a.at(0) << ' ' << p.second -> b.at(0) << std::endl;
}
return 0;
}
Output:
12 16 - 3 4
16 12 - 1 2

How do I convert values from a vector to a map in c++?

I want to do something like this. Is there a stl algorithm that does this easily?
for each(auto aValue in aVector)
{
aMap[aValue] = 1;
}
If you have a vector of pairs, where the first item in the pair will be the key for the map, and the second item will be the value associated with that key, you can just copy the data to the map with an insert iterator:
std::vector<std::pair<std::string, int> > values {
{"Jerry", 1},
{ "Jim", 2},
{ "Bill", 3} };
std::map<std::string, int> mapped_values;
std::copy(values.begin(), values.end(),
std::inserter(mapped_values, mapped_values.begin()));
or, you could initialize the map from the vector:
std::map<std::string, int> m2((values.begin()), values.end());
Maybe like this:
std::vector<T> v; // populate this
std::map<T, int> m;
for (auto const & x : v) { m[x] = 1; }
You might std::transform the std::vector into a std::map
std::vector<std::string> v{"I", "want", "to", "do", "something", "like", "this"};
std::map<std::string, int> m;
std::transform(v.begin(), v.end(), std::inserter(m, m.end()),
[](const std::string &s) { return std::make_pair(s, 1); });
This creates std::pairs from the vector's elements, which in turn are inserted into the map.
Or, as suggested by #BenFulton, zipping two vectors into a map
std::vector<std::string> k{"I", "want", "to", "do", "something", "like", "this"};
std::vector<int> v{1, 2, 3, 4, 5, 6, 7};
std::map<std::string, int> m;
auto zip = [](const std::string &s, int i) { return std::make_pair(s, i); };
std::transform(k.begin(), k.end(), v.begin(), std::inserter(m, m.end()), zip);
Assuming items in vector are related in order, maybe this example can help :
#include <map>
#include <vector>
#include <string>
#include <iostream>
std::map<std::string, std::string> convert_to_map(const std::vector<std::string>& vec)
{
std::map<std::string, std::string> mp;
std::pair<std::string, std::string> par;
for(unsigned int i=0; i<vec.size(); i++)
{
if(i == 0 || i%2 == 0)
{
par.first = vec.at(i);
par.second = std::string();
if(i == (vec.size()-1))
{
mp.insert(par);
}
}
else
{
par.second = vec.at(i);
mp.insert(par);
}
}
return mp;
}
int main(int argc, char** argv)
{
std::vector<std::string> vec;
vec.push_back("customer_id");
vec.push_back("1");
vec.push_back("shop_id");
vec.push_back("2");
vec.push_back("state_id");
vec.push_back("3");
vec.push_back("city_id");
// convert vector to map
std::map<std::string, std::string> mp = convert_to_map(vec);
// print content:
for (auto it = mp.cbegin(); it != mp.cend(); ++it)
std::cout << " [" << (*it).first << ':' << (*it).second << ']';
std::cout << std::endl;
return 0;
}
A very generic approach to this, since you didn't specify any types, can be done as follows:
template<class Iterator, class KeySelectorFunc,
class Value = std::decay_t<decltype(*std::declval<Iterator>())>,
class Key = std::decay_t<decltype(std::declval<KeySelectorFunc>()(std::declval<Value>()))>>
std::map<Key, Value> toMap(Iterator begin, Iterator end, KeySelectorFunc selector) {
std::map<Key, Value> map;
std::transform(begin, end, std::inserter(map, map.end()), [selector](const Value& value) mutable {
return std::make_pair(selector(value), value);
});
return map;
}
Usage:
struct TestStruct {
int id;
std::string s;
};
std::vector<TestStruct> testStruct = {
TestStruct{1, "Hello"},
TestStruct{2, "Hello"},
TestStruct{3, "Hello"}
};
std::map<int, TestStruct> map = toMap(testStruct.begin(), testStruct.end(),
[](const TestStruct& t) {
return t.id;
}
);
for (const auto& pair : map) {
std::cout << pair.first << ' ' << pair.second.id << ' ' << pair.second.s << '\n';
}
// yields:
// 1 1 Hello
// 2 2 Hello
// 3 3 Hello
The parameter selector function is used to select what to use for the key in the std::map.
Try this:
for (auto it = vector.begin(); it != vector.end(); it++) {
aMap[aLabel] = it;
//Change aLabel here if you need to
//Or you could aMap[it] = 1 depending on what you really want.
}
I assume this is what you are trying to do.
If you want to update the value of aLabel, you could change it in the loop. Also, I look back at the original question, and it was unclear what they wanted so I added another version.
Yet another way:
#include <map>
#include <vector>
#include <boost/iterator/transform_iterator.hpp>
int main() {
using T = double;
std::vector<T> v;
auto f = [](T value) { return std::make_pair(value, 1); };
std::map<T, int> m(boost::make_transform_iterator(v.begin(), f),
boost::make_transform_iterator(v.end(), f));
}
But I don't think it beats range-for loop here in terms of readability and execution speed.
For converting values of a array or a vector directly to map we can do like.
map<int, int> mp;
for (int i = 0; i < m; i++)
mp[a[i]]++;
where a[i] is that array we have with us.