Push_back map into vector - c++

How can I push_back a std::map element into std::vector?
std::vector<std::map<int, int>> v;
// Error
v.push_back(std::make_pair(0, 1))
What cause this error?

Using
v.push_back(std::make_pair(0, 1))
is a problem since a std::pair cannot be converted to a std::map. You can resolve the problem using one of the following methods that I can think of.
Method 1
If you can use a C++11 compiler,
v.push_back({{0, 1}});
Method 2
std::map<int, int> m;
m.insert(std::make_pair(0, 1));
v.push_back(m);
Method 3
std::map<int, int> m;
v.push_back(m);
v.back().insert(std::make_pair(0, 1));

std::vector<std::map<int, int>> v;
means you are declaring vector of maps!
push_back a map into vector, like this
v.push_back({std::make_pair(0, 1)}); //Needs C++11
OR
std::map<int, int> map1;
map1.insert(std::make_pair(0, 1));
v.push_back(map1);
push_back'ng a pair will obviously result into a compilation error.

You can push a map into your Data Structure, std::vector<std::map<int, int>> v. not a pair i.e. element of map.
So, do as following.
std::map<int,int> t;
t.insert(std::make_pair(0, 1));
v.push_back(t);
or in case of C++11
v.push_back({{1,2}});
Or alternatively you can go for emplace_back too.
void emplace_work_around(
std::vector<std::map<int, int>>& v,
std::initializer_list<std::pair<const int,int>> item
)
{
v.emplace_back(item);
}
int main()
{
std::vector<std::map<int, int>> v;
emplace_work_around(v,{{1,2}});
}

Related

Erase element by value from vector of pairs

Since C++20, we can erase an element by value from a vector by doing, for example:
std::vector<int> v = {10,20,30,40,50};
std::erase(v,30);
That's really convenient and all not to mention there's also std::erase_if.
However, what if we have a vector of pairs and we want to erase, only if the second value of the pair matches?
std::pair<int, std::string> foo = std::make_pair(1,"1");
std::pair<int, std::string> foo2 = std::make_pair(2,"2");
std::vector< std::pair<int, std::string> > v;
v.push_back(foo);
v.push_back(foo2);
std::erase(v, make_pair(1,"2")); //This is not going to work!
So, is there a way to erase the element by the second value from a vector of pairs?
It would be something like:
std::erase_if(v, [](const auto& p){ return p.second == "2"; });
Demo

How to insert value in map?

I am having an issue with map.
map<int, map<int , int>> my_map;
I am using insert() like:
my_map.insert(10, my_map.second.insert(20, 30));
but it's not working.
The method to insert into map in dictionary is add(key,value)
Your code my_map.insert(10, my_map.second.insert(20, 30)); will throw an error as `second' is not a method that can be called on map.
Here is what you can do to solve this issue:
map<int, map<int , int>> my_map;
map<int, int> my__second_map = new map<int,int>();
my_second_map.add(20,30);
my_map.add(10,my__second_map);
You need an iterator of map type to call second.
You could also use below code using map insert. You may also use pair data type.
#include <map>
#include <iostream>
int main()
{
std::map<int, std::map<int , int> > my_map;
std::map<int,int> data;
data.insert(std::pair<int,int>(20,30));
my_map.insert(std::pair<int,std::map<int,int> >(10, data));
return 0;
}

How to effectively reuse mapped value

The program has the following input data:
std::map<std::string, std::vector<int> >
Now I need to convert this data structure into the following:
std::map<int, std::vector<int> >
Fo example:
"key1" => 1
"key2" => 20
etc.
Only the key type is changed, the mapped value is unchanged.
The question is that how I can reuse the mapped key std::vector<int> effectively so that the mappped value is not copied since there is no need to do so.
Here are two ideas that come to my mind:
////////////////////////////////////////////////////
Solution 1>
redefine the interface
from
std::map<int, std::vector<int> >
to
std::map<int, std::vector<int>* >
////////////////////////////////////////////////////
Solution 2>
redefine the interface
from:
std::map<std::string, std::vector<int> >
std::map<int, std::vector<int> >
to:
std::map<std::string, boost::shared_ptr<std::vector<int>> >
std::map<int, boost::shared_ptr<std::vector<int>> >
In both cases, the cost of the copy is simply a copy of a pointer.
Any comment is appreciated
C++11 provides move-operations to move one object to another without copying. VS 2010 should have the necessary machinery implemented. With this, assuming you have a mapping for old to new keys, you can remap the data like this:
std::map<std::string, std::vector> m1;
std::map<int, std::vector> m2;
std::map<std::string, int> keymap;
for (auto i=m1.begin(); i != m1.end(); ++i)
{
m2[keymap[i->first]] = std::move(i->second);
}
Now, all vectors have been moved to a new map leaving the map m1 in an undefined, but destructible state.
If C++11 (as available in VS2010) is not an option, swap the new map with the old one:
std::map<std::string, std::vector> m1;
std::map<int, std::vector> m2;
std::map<std::string, int> keymap;
for (std::map<std::string, std::vector>::iterator i=m1.begin(); i != m1.end(); ++i)
{
m2[keymap[i->first]].swap(i->second);
}

C++ Copy a vector of pair<int,int> to a vector<int>

I've a vector of pair which I need to copy them linearly to a vector of ints. I've the following code which works well, but I'm not sure if it's safe considering struct padding issues in C++.
std::vector < std::pair<int, int> > test_vector;
for (int i=0;i<5;i++) {
test_vector.push_back(std::make_pair(i,i*5));
}
std::vector<int> int_vec(test_vector.size() * 2);
std::copy(reinterpret_cast<int*>(&(*test_vector.begin())),reinterpret_cast<int*>(&(*test_vector.end())),int_vec.begin());
Now, my question is - Is the above code safe? If not, is there an elegant way to do it without writing a loop?
How about std::transform and a lambda function ?
std::vector<int> v;
std::transform(test_vector.begin(), test_vector.end(), std::back_inserter(v),
[&v](const std::pair<int, int> &p)
{ v.push_back( p.first);
return p.second ;});
If you can't use C++11, and probably "hate" doing linear copying using loops
You can use functor like:
struct X{
X(std::vector<int> &x) :v(x){}
int operator () (const std::pair<int, int> &p)
{
v.push_back(p.first);
return p.second;
}
std::vector<int> &v;
};
std::vector<int> v; //Final vector
std::transform(test_vector.begin(),
test_vector.end(),
std::back_inserter(v),
X(v));
std::vector<int> ::iterator it;
for(it=v.begin() ; it!=v.end() ;++it)
std::cout<<*it<<" ";
You don't need any fanciness for this problem. A simple for loop will do, especially if you can't use C++11
std::vector < std::pair<int, int> > test_vector;
std::vector<int> int_vec; int_vec.reserve(test_vector.size() * 2);
for (std::vector < std::pair<int, int> >::const_iterator it = test_vector.begin(), end_it = test_vector.end(); it != end_it; ++it)
{
int_vec.push_back(it->first);
int_vec.push_back(it->second);
}
You're right to be concerned about structure padding issues, but I think you haven't really faced the central assumption that your code is making:
Can I treat a std::pair<int, int> as an array of two integers, with the .first being the first element in the array and .second being the second element?
From a "correctness" point of view, I'd say "no". You've identified padding issues, but there's also the ordering of the fields. There's really no guarantee that .first has a lower memory address than .second.
From a "practical" point of view, I'd be quite surprised your that code did not work. [ Edit: Neil has pointed out a concrete example where there are padding issues; so color me surprised. Besides being "bad form", I now consider the code broken in practice. ]
As for a solution, you can use for_each with a custom action that pushes both elements of the pair (untested code)
struct action {
action ( vector<int> & target ) : t_(target) {}
void operator () ( const pair &p ) const
{ t_.push_back(p.first); t_.push_back(p.second); }
private:
vector<int> &t_;
}
for_each ( test_vector.begin(), test_vector.end(), action(v));
A reinterpret_cast is usually bad news. Wouldn't you be better off reserve()ing enough space in the destination vector and then calling std::for_each on the source vector of pairs and then have the function/lambda push_back both first and second into the destination vector ?

Search in vector<std::pair<int, vector<int> > >

I would like to search within a vector<std::pair<int, vector<int> > >. This won't work due to the vector parameters:
std::vector<std::pair<int, std::vector<int> > > myVec;
iterator = find(myVec.begin(), myVec.end(), i);
Search would be on the first std::pair template parameter (int), in order to get the vector associated with it.
std::vector<std::pair<int, std::vector<int> > > myVec;
This requires C++0x for the lambda expression:
typedef std::pair<int, std::vector<int>> pair_type
std::find_if(myVec.begin(), myVec.end(), [i](pair_type const& pair)
{ return pair.first == i; });
If you're not using C++0x then either roll out your own loop or use something like Boost.Phoenix/Boost.Lambda.
Or, for both cases, why not use std::map?
You could make do with the following (pretty ugly) functoid:
struct FindFirst {
FindFirst(int i) : toFind(i) { }
int toFind;
bool operator()
( const std::pair<int, std::vector<int> > &p ) {
return p.first==toFind;
}
};
using it like this ( I couldn't get bind2nd to work - that's why I used the c'tor ):
int valueToFind = 4;
std::find_if(myVec.begin(), myVec.end(), FindFirst(valueToFind));
I think what you would like is a map:
std::map< int, vector< int > > foo;
You can then add elements, search by key etc:
int key = 4; //This will be the key
vector<int> value(5, 4); //Fill some values (5 4's in this case) into the vector
foo[key]=value; //Adds the pair to the map. Alternatively;
foo.insert( make_pair(key, value) ); //Does the same thing (in this context)
Looking at the way you've done things though, you might be wanting a std::multimap (which allows multiple values to have the same key) Class docs here
You're trying to map an int to a vector of int.
So try map<int, vector<int> >.
The second template parameter of a vector is the allocator - your compiler can probably puzzle out what you wanted to say, the declaration is wrong anyway. What you probably want is some sort of map type, like iammilind suggested.