The obvious way to convert a bimap to std::map, doesnt seem to work. Is below the correct/good way to convert? Is there a better/shorter way?
typedef boost::bimap<int, std::string> MapType;
MapType _bimap;
//Fill _bimap
MapType::left_map& lmap = _bimap.left;
//std::map<int, std::string> bmap(lmap.begin(), lmap.end()); //THIS DOESNT WORK
std::map<int, std::string> bmap;
BOOST_FOREACH(MapType::left_const_reference entry, lmap)
{
bmap[entry.first] = entry.second;
}
The values from a bimap cannot be directly assigned to thos of a map because there is a problem of type (ignoring the more obvious problem of const-ness of the value):
When a bimap left view iterator is dereferenced the return type is signature-compatible with a std::pair< const A, const B >
(source)
And :
A type is signature-compatible with other type if it has the same signature for functions and metadata. Preconditions, postconditions and the order of operations need not be the same.
That means that there is no guarantee that your bimap value_type is assignable or copyable to a map value_type. In fact it is not:
typedef boost::bimap<int, std::string> BiMapType;
typedef std::map<int, std::string> MapType;
BiMapType bimap;
BiMapType::left_value_type t1 = *(bimap.left.begin()); // Mandatory for compilation on my version at least
MapType::value_type t2(t1);
That will fail horribly (same kind of thing if you try t2 = t1;)
So either you find a way to convert your value_types either you keep with a for_each/transform/copy ... idiom.
There is a neat solution signaled here in comment by #CharlesPehlivanian (that he will maybe provide as an answer also), that is to use boost::trasnform_iterator.
For that you have to provide a transformer functor (it does not work with a raw lambda, you have to use a struct with operator() and result_type or a std::function) that will convert the input iterator value to the output one:
typedef std::function<MapType::value_type (const BiMapType::left_value_type&)>
Transformer;
Transformer transformer_func = [](const BiMapType::left_value_type& elem)
{
return std::make_pair(elem.first, elem.second);
};
Then you just have to wrap begin and end iterator with boost::make_transform_iterator:
auto begin = boost::make_transform_iterator(bimap.left.begin(), transformer_func);
auto end = boost::make_transform_iterator(bimap.left.end(), transformer_func);
Here is the whole code:
#include <boost/bimap.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <map>
int main(int argc, char const *argv[])
{
typedef boost::bimap<int, std::string> BiMapType;
typedef std::map<int, std::string> MapType;
typedef std::function<MapType::value_type (const BiMapType::left_value_type&)>
Transformer;
BiMapType bimap;
Transformer transformer_func = [](const BiMapType::left_value_type& elem)
{
return std::make_pair(elem.first, elem.second);
};
auto begin = boost::make_transform_iterator(bimap.left.begin(), transformer_func);
auto end = boost::make_transform_iterator(bimap.left.end(), transformer_func);
MapType map(begin, end);
return 0;
}
http://coliru.stacked-crooked.com/a/8fae0d47ca4b72a1
Related
I want a map in c++, in which its key is combination of multiple values. I can use both stl and boost also.
Key values can be string/integers something like below
typedef value_type int;
typedef key(string, template(string,int), template(string,int)) key_type;
typedef map(key_type, value_type) map_type;
map_type map_variable;
map_variable.insert(key_type("keyStrning1", 1, "keyString2"), 4);
map_variable.insert(key_type("keyStrning3", 1, "keyString2"), 5);
Now this map will contain two entries and i shall be able to find it like below:
map_variable.find(key_type("keyStrning3", 1, "keyString2")).
I can use nested maps , but i want to know is there any convenient solution for this using either boost or c++ stl.
You can use boost::variant (or std::variant when C++17 will be ready).
#include <tuple>
#include <map>
#include <utility>
#include <boost/variant/variant.hpp>
typedef int ValueType;
typedef boost::variant<std::string, int> StrOrInt;
typedef std::tuple<std::string, StrOrInt, StrOrInt> KeyType;
typedef std::map<KeyType, ValueType> MapType;
int main(int argc, char *argv[]) {
MapType amap;
amap.insert(std::make_pair(
std::make_tuple("string1", "string2", 3), <--- key
4)); // <--- value
auto finder = amap.find(std::make_tuple("string1", "string2", 3));
std::cout << finder->second << '\n'; // <--- prints 4
return 0;
}
I want to implement a map, which maps a string to a generic vector.
I want to do this:
std::map<std::string, std::vector<class T> > myMap;
Assuming the proposed myMap had the following inserted into it, it could be used as such:
vector<int> intVec = myMap["ListOfInts"]; // Works because "ListOfInts" maps to a vector<int>
vector<string> stringVec = myMap["ListOfStrings"]; // Works because "ListOfInts" maps to a vector<string>
When I declare the map with the above syntax the compiler has a heart attack.
Can anybody make any suggestions? Or a better associate array option in C++ (suggest non-boost before boost).
Since you know the type you want when you are writing your code, I propose this approach (untested):
// base class for any kind of map
class BaseMap {
public:
virtual ~BaseMap() {}
};
// actual map of vector<T>
template<typename T>
class MapT : public BaseMap, public std::map<std::string, std::vector<T>> {};
class MultiMap {
public:
template<typename T>
std::vector<T>& get(const std::string& key) {
std::unique_ptr<BaseMap>& ptr = maps_[std::type_index(typeid(T))];
if (!ptr) ptr.reset(new MapT<T>());
return ptr->second[key];
}
private:
std::map<std::type_index, std::unique_ptr<BaseMap>> maps_;
}
int main() {
MultiMap map;
std::vector<int>& intVec = map.get<int>("ListOfInts");
std::vector<std::string>& stringVec = map.get<std::string>("ListOfStrings");
}
Maybe this could work for you:
template <typename T>
class MyMap {
std::map<std::string, std::vector<typename T> > map;
public:
/*...*/
};
As mattnewport said boost::variant is one option.
Or to support any types, use boost::any by explicit using any_cast.
Considering boost might be heavy weight, maybe you can reinvent the wheel and simplify it, so that is non boost any more? lol
With C++11, you can use using, it does exactly what you want:
#include <vector>
#include <map>
#include <string>
template<typename T> using mymap = std::map<std::string, std::vector<T>>;
int main()
{
mymap<int> intmap;
mymap<std::string> stringmap;
std::vector<int> intvec = intmap["test"];
std::vector<std::string> stringvec = stringmap["test"];
return 0;
}
Live Demo
Template arguments must be decided compile time. If you want each key of your map to correspond to a vector of a different type, it won't really work. You can get around it with a polymorphic container that returns a void* that you cast to the correct type, but I would suggest trying to find another way to do whatever you want to do with your map first.
I am interested in building an std::unordered_map< K, V> Map; where V is something like Map::iterator. Specifically I want to make V this vector< Pair< double, Map::iterator> >;
. As just stated this is a recursive type in C++ which is not allowed by the standard.
However, the operations of begin(), end() and operator++() on the unordered_map do not need any knowledge of Map::mapped_type to be well defined, so, in principle it seems that Map::iterator should be able to be defined independently of unordered_map.
So I wonder is there a way to define:
typedef std::unordered_map_iterator< K> iterator;
typedef std::unordered_map_const_iterator< K> const_iterator;
then create:
typedef std::unordored_map< K, iterator> Map;
such that, map.insert( std::make_pair( K(), map.begin()); makes sense?
For example what about something like the below?
typedef std::unordered_map< K, V> Premap;
typedef std::unordered_map< K, Premap::iterator> Map;
In partial answer, the above suggestion produces a template deduction error, as expected. But nevertheless something like this should be do-able.
#include <unordered_map>
#include <iostream>
#include <string>
#include <utility>
typedef std::string K; //these two types are arbitrary
typedef double V; //chosen just for completeness sake.
typedef std::unordered_map< K, V> Premap;
typedef std::unordered_map< K, Premap::iterator> Map;
int main( int argc, char ** argv){
Map test;
test.insert( std::make_pair( std::string( "foo"), test.end()));
return 0;
}
Creating a standard container which contains iterators to itself is impossible. However, there are alternative approaches which behave the same.
Solution 1
unordered_map requires unique keys. Therefore, simply use std::string as the value type, and look it up in the map when necessary. The average algorithmic complexity of the lookup is the same in both cases - O(1).
Example: let's say you want to represent this data:
foo -> bar
bar -> baz
baz -> barney
fred -> (nothing)
barney -> (nothing)
Then you would write this to construct the data structure:
std::unordered_map<std::string, std::string> Map;
Map m;
m.insert(std::make_pair(std::string("foo"), std::string("bar")));
m.insert(std::make_pair(std::string("bar"), std::string("baz")));
m.insert(std::make_pair(std::string("baz"), std::string("barney")));
m.insert(std::make_pair(std::string("fred"), std::string("")));
m.insert(std::make_pair(std::string("barney"), std::string("")));
To walk along the chains in this structure, you could use code like this:
Map::iterator i = m.find("foo");
while (i != m.end() && !i->second.empty()) {
i = m.find(i->second);
}
Note that any string which does not appear as a key could be used to mark the end of the chain.
Solution 2
Use boost::ptr_unordered_set and store the pointer to the next value in the value itself. Add appropriate equality and comparison operators, so that the pointer is ignored in the set. Note that this adds an extra level of indirection, but this is unavoidable.
struct ChainElement
: boost::equality_comparable<ChainElement>
{
std::string key;
ChainElement *next;
ChainElement(std::string const &k, ChainElement *n = NULL)
: key(k), next(n)
{}
bool operator==(ChainElement const &other) const {
return key == other.key;
}
};
namespace std {
template <>
hash<ChainElement>::operator()(ChainElement const &ce) const {
return std::hash(ce.key);
};
}
Set up the structure e.g. like this:
#include <boost/ptr_container/ptr_unordered_set.hpp>
// ...
boost::ptr_unordered_set<ChainElement> m;
m.insert(new ChainElement("foo"));
m.insert(new ChainElement("bar"));
m.insert(new ChainElement("baz"));
m.insert(new ChainElement("fred"));
m.insert(new ChainElement("barney"));
m.find("foo")->next = &*m.find("bar");
m.find("bar")->next = &*m.find("baz");
m.find("baz")->next = &*m.find("barney");
Then to walk the structure:
ChainElement *elem = &*m.find("foo");
while (elem != NULL) {
// do something
elem = elem->next;
}
Using boost::ptr_unordered_set rather than std::unordered_set guarantees that the objects will be deleted when the container holding them is deleted.
This question already has answers here:
How to retrieve all keys (or values) from a std::map and put them into a vector?
(24 answers)
Closed 1 year ago.
Working my way through Effective STL at the moment. Item 5 suggests that it's usually preferable to use range member functions to their single element counterparts. I currently wish to copy all the values in a map (i.e. - I don't need the keys) to a vector.
What is the cleanest way to do this?
You could probably use std::transform for that purpose. I would maybe prefer Neils version though, depending on what is more readable.
Example by xtofl (see comments):
#include <map>
#include <vector>
#include <algorithm>
#include <iostream>
template< typename tPair >
struct second_t {
typename tPair::second_type operator()( const tPair& p ) const { return p.second; }
};
template< typename tMap >
second_t< typename tMap::value_type > second( const tMap& m ) { return second_t< typename tMap::value_type >(); }
int main() {
std::map<int,bool> m;
m[0]=true;
m[1]=false;
//...
std::vector<bool> v;
std::transform( m.begin(), m.end(), std::back_inserter( v ), second(m) );
std::transform( m.begin(), m.end(), std::ostream_iterator<bool>( std::cout, ";" ), second(m) );
}
Very generic, remember to give him credit if you find it useful.
You can't easily use a range here because the iterator you get from a map refers to a std::pair, where the iterators you would use to insert into a vector refers to an object of the type stored in the vector, which is (if you are discarding the key) not a pair.
I really don't think it gets much cleaner than the obvious:
#include <map>
#include <vector>
#include <string>
using namespace std;
int main() {
typedef map <string, int> MapType;
MapType m;
vector <int> v;
// populate map somehow
for( MapType::iterator it = m.begin(); it != m.end(); ++it ) {
v.push_back( it->second );
}
}
which I would probably re-write as a template function if I was going to use it more than once. Something like:
template <typename M, typename V>
void MapToVec( const M & m, V & v ) {
for( typename M::const_iterator it = m.begin(); it != m.end(); ++it ) {
v.push_back( it->second );
}
}
With C++11 we have the fancy new for loop:
for (const auto &s : schemas)
names.push_back(s.second);
where schemas is a std::map and names is an std::vector.
This populates the array (names) with values from the map (schemas); change s.second to s.first to get an array of keys.
#include <algorithm> // std::transform
#include <iterator> // std::back_inserter
std::transform(
your_map.begin(),
your_map.end(),
std::back_inserter(your_values_vector),
[](auto &kv){ return kv.second;}
);
Sorry that I didn't add any explanation - I thought that code is so simple that is doesn't require any explanation.
So:
transform( beginInputRange, endInputRange, outputIterator, unaryOperation)
this function calls unaryOperation on every item from inputIterator range (beginInputRange-endInputRange). The value of operation is stored into outputIterator.
If we want to operate through whole map - we use map.begin() and map.end() as our input range. We want to store our map values into vector - so we have to use back_inserter on our vector: back_inserter(your_values_vector). The back_inserter is special outputIterator that pushes new elements at the end of given (as paremeter) collection.
The last parameter is unaryOperation - it takes only one parameter - inputIterator's value. So we can use lambda:
[](auto &kv) { [...] }, where &kv is just a reference to map item's pair. So if we want to return only values of map's items we can simply return kv.second:
[](auto &kv) { return kv.second; }
I think this explains any doubts.
If you are using the boost libraries, you can use boost::bind to access the second value of the pair as follows:
#include <string>
#include <map>
#include <vector>
#include <algorithm>
#include <boost/bind.hpp>
int main()
{
typedef std::map<std::string, int> MapT;
typedef std::vector<int> VecT;
MapT map;
VecT vec;
map["one"] = 1;
map["two"] = 2;
map["three"] = 3;
map["four"] = 4;
map["five"] = 5;
std::transform( map.begin(), map.end(),
std::back_inserter(vec),
boost::bind(&MapT::value_type::second,_1) );
}
This solution is based on a post from Michael Goldshteyn on the boost mailing list.
Using lambdas one can perform the following:
{
std::map<std::string,int> m;
std::vector<int> v;
v.reserve(m.size());
std::for_each(m.begin(),m.end(),
[&v](const std::map<std::string,int>::value_type& p)
{ v.push_back(p.second); });
}
Here is what I would do.
Also I would use a template function to make the construction of select2nd easier.
#include <map>
#include <vector>
#include <algorithm>
#include <memory>
#include <string>
/*
* A class to extract the second part of a pair
*/
template<typename T>
struct select2nd
{
typename T::second_type operator()(T const& value) const
{return value.second;}
};
/*
* A utility template function to make the use of select2nd easy.
* Pass a map and it automatically creates a select2nd that utilizes the
* value type. This works nicely as the template functions can deduce the
* template parameters based on the function parameters.
*/
template<typename T>
select2nd<typename T::value_type> make_select2nd(T const& m)
{
return select2nd<typename T::value_type>();
}
int main()
{
std::map<int,std::string> m;
std::vector<std::string> v;
/*
* Please note: You must use std::back_inserter()
* As transform assumes the second range is as large as the first.
* Alternatively you could pre-populate the vector.
*
* Use make_select2nd() to make the function look nice.
* Alternatively you could use:
* select2nd<std::map<int,std::string>::value_type>()
*/
std::transform(m.begin(),m.end(),
std::back_inserter(v),
make_select2nd(m)
);
}
One way is to use functor:
template <class T1, class T2>
class CopyMapToVec
{
public:
CopyMapToVec(std::vector<T2>& aVec): mVec(aVec){}
bool operator () (const std::pair<T1,T2>& mapVal) const
{
mVec.push_back(mapVal.second);
return true;
}
private:
std::vector<T2>& mVec;
};
int main()
{
std::map<std::string, int> myMap;
myMap["test1"] = 1;
myMap["test2"] = 2;
std::vector<int> myVector;
//reserve the memory for vector
myVector.reserve(myMap.size());
//create the functor
CopyMapToVec<std::string, int> aConverter(myVector);
//call the functor
std::for_each(myMap.begin(), myMap.end(), aConverter);
}
Why not:
template<typename K, typename V>
std::vector<V> MapValuesAsVector(const std::map<K, V>& map)
{
std::vector<V> vec;
vec.reserve(map.size());
std::for_each(std::begin(map), std::end(map),
[&vec] (const std::map<K, V>::value_type& entry)
{
vec.push_back(entry.second);
});
return vec;
}
usage:
auto vec = MapValuesAsVector(anymap);
I thought it should be
std::transform( map.begin(), map.end(),
std::back_inserter(vec),
boost::bind(&MapT::value_type::first,_1) );
We should use the transform function from STL algorithm, the last parameter of transform function could be a function object, function pointer or a lambda function that convert item of map to item of vector. This case map have items have type pair that need to convert to item that has int type for vector. Here is my solution that I use lambda function:
#include <algorithm> // for std::transform
#include <iterator> // for back_inserted
// Map of pair <int, string> need to convert to vector of string
std::map<int, std::string> mapExp = { {1, "first"}, {2, "second"}, {3, "third"}, {4,"fourth"} };
// vector of string to store the value type of map
std::vector<std::string> vValue;
// Convert function
std::transform(mapExp.begin(), mapExp.end(), std::back_inserter(vValue),
[](const std::pair<int, string> &mapItem)
{
return mapItem.second;
});
The other answers mention std::transform, and semantically it's the right choice. But in practice std::accumulate might fit better for this task, because:
it allows adding const to the resulting vector;
it just looks nicer, truly functional-style.
Example (using C++17 syntax):
#include <numeric> // for std::accumulate. Note that it's not in <algorithm> where std::transform is located, thanks to Anton Krug for pointing this out
auto map = std::map<int,bool>{};
map[0]=true;
map[1]=false;
const auto mapValues = std::accumulate(map.begin(), map.end(), std::vector<bool>(map.size()), [](auto& vector, const auto& mapEntry) {
vector.push_back(mapEntry.second);
return vector;
});
Surprised nobody has mentioned the most obvious solution, use the std::vector constructor.
template<typename K, typename V>
std::vector<std::pair<K,V>> mapToVector(const std::unordered_map<K,V> &map)
{
return std::vector<std::pair<K,V>>(map.begin(), map.end());
}
How can I use BOOST_FOREACH efficiently (number-of-character/readability-wise) with a boost::ptr_map?
Kristo demonstrated in his answer that it is possible to use BOOST_FOREACH with a ptr_map, but it does not really save me any typing (or makes my code really more readable) than iterating over the ptr_map with an iterator:
typedef boost::ptr_container_detail::ref_pair<int, int* const> IntPair;
BOOST_FOREACH(IntPair p, mymap) {
int i = p.first;
}
// vs.
boost::ptr_map<int, T>::iterator it;
for (it = mymap.begin(); it != mymap.end(); ++it) {
// doSomething()
}
The following code is somewhere along the lines what I wish for. It follows the standard way on how to use BOOST_FOREACH with a std::map. Unfortunately this does not compile:
boost::ptr_map<int, T> mymap;
// insert something into mymap
// ...
typedef pair<int, T> IntTpair;
BOOST_FOREACH (IntTpair &p, mymap) {
int i = p.first;
}
As STL style containers, the pointer containers have a value_type typedef that you can use:
#include <boost/ptr_container/ptr_map.hpp>
#include <boost/foreach.hpp>
int main()
{
typedef boost::ptr_map<int, int> int_map;
int_map mymap;
BOOST_FOREACH(int_map::value_type p, mymap)
{
}
}
I find that using a typedef for the container makes the code a lot easier to write.
Also, you should try to avoid using the contents of detail namespaces in boost, it's a boost convention that they contain implementation details.
I just ran into the same problem today. Unfortunately, Daniel's suggestion will not work with a constant reference to a map. In my case, the ptr_map was a member of a class, and I wanted to loop through it in a const member function. Borrowing Daniel's example, this is what I had to do in my case:
#include "boost/ptr_container/ptr_map.hpp"
#include "boost/foreach.hpp"
int main()
{
typedef boost::ptr_map<int, int> int_map;
int_map mymap;
const int_map& mymap_const_ref(mymap);
BOOST_FOREACH(int_map::const_iterator::value_type p, mymap_const_ref)
{
}
}
It seems that int_map::const_iterator::value_type is equivalent to boost::ptr_container_detail::ref_pair<int, const int* const>.
Save yourself the typing and improve readability by using tuples:
boost::ptr_map<int, T> mymap;
int key;
T * value;
BOOST_FOREACH(boost::tie(key, value), mymap)
{
...
}
This example code compiled for me with g++ 4.1.2:
#include "boost/ptr_container/ptr_map.hpp"
#include "boost/foreach.hpp"
int main()
{
boost::ptr_map<int, int> mymap;
typedef boost::ptr_container_detail::ref_pair<int, int* const> IntPair;
BOOST_FOREACH(IntPair p, mymap)
{
int i = p.first;
}
return 0;
}
I use this homebrew template which adds an iteration type which can be handled by BOOST_FOREACH
namspace homebrew
{
template
<
class Key,
class T,
class Compare = std::less<Key>,
class CloneAllocator = boost::heap_clone_allocator,
class Allocator = std::allocator< std::pair<const Key,void*> >
>
class ptr_map :
public boost::ptr_map<Key,T,Compare,CloneAllocator,Allocator>
{
public:
typedef boost::ptr_container_detail::ref_pair<Key,const T* const> const_ref;
typedef boost::ptr_container_detail::ref_pair<Key,T* const> ref;
};
}
Let's assume that foo and bar are two of your favorite types ;)
typedef homebrew::ptr_map<foo,bar> Map;
int f( const Map& m )
{
BOOST_FOREACH(Map::const_ref v, m)
{
v.first; // foo
v.second; // const bar* const
}
}
or
int f( Map& m )
{
BOOST_FOREACH(Map::ref v, m)
{
v.first; // foo
v.second; // bar* const
}
}
Which one you have to use doesn't seem to depend on the way you use it in the loop (const or non-const) but on the map's constness!! So the following will end up in an error...
int f( Map& m )
{
BOOST_FOREACH(Map::const_ref v, m) // can't use const_ref because m isn't const
{
...
}
}
Weird! isn't it?
The greatest thing to me is that of all this solutions which were suggested here, this is the first one which is handled correctly by the Eclipse CDT syntax coloring (when using the 'Code/Problem' syntax coloring attribute).
It should compile without the reference:
BOOST_FOREACH (IntTpair p, mymap)
I think the problem is that maps do not actually store objects as pairs, but as a tree structure with the first element as the key, so BOOST_FOREACH can't get a reference to a pair but it can create a temporary copy of one.
using ::value_type won't let you const-iterate through the container. I use iterator reference types
typedef boost::ptr_map< myKey, myPtrType > MyMap;
MyMap m;
BOOST_FOREACH( MyMap::iterator::reference it, m )
do_something( it.second );
BOOST_FOREACH( MyMap::const_iterator::reference it, m )
do_something_const( it.second );
In the end, I went for declaring the iteration variable before the loop.
std::pair<std::string, TrailStep*> step;
BOOST_FOREACH(step, m_steps)
{
SAFE_DELETE(step.second);
}
But indeed, there ought to be a simpler way. (Use D instead?)
You might try this uber-cool way to iterate over maps, ptr or otherwise:
https://svn.boost.org/trac/boost/attachment/ticket/3469/foreach_field.hpp
// no typedef needed
BOOST_FOREACH_FIELD((int i)(const T& t), mymap)
// do something with i or t instead of first/second
I'm not sure it will work with a template parameter, but maybe you used that just for abstraction.