map with key which is combination of multiple values in c++ - c++

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

Related

Best way to build this data structure

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.

Convert boost::bimap to std::map

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

Recursive Typedef in C++

I want to write a typedefinition in c++, but do not know if something I want to implement is legal. Let's say I want to do a typedef of a vector of boost variant types, which point to an int, or another vector of the same type. So, would this be legal and would the compiler complain?
typedef std::vector<boost::variant<int *, boost::variant<int *, IntBranch*>> IntBranch;
You can use boost::make_recursive_variant for that purpose:
#include <boost/variant.hpp>
typedef boost::make_recursive_variant<
int*,
std::vector< boost::recursive_variant_ >
>::type IntBranch;
And this is how you would use it:
#include <vector>
int main()
{
typedef boost::make_recursive_variant<
int*,
std::vector< boost::recursive_variant_ >
>::type IntBranch;
int x = 42;
IntBranch ib = &x;
std::vector<IntBranch> v;
v.push_back(ib);
IntBranch ib2 = v;
// ...
}
And here is a live example.

__gnu_cxx hash map with keys of type std::pair<std::string, unsigned int>?

Since std::pair<std::string, unsigned int> is not defined for __gnu_cxx hash map, how do I create a __gnu_cxx hash map with keys of type std::pair<std::string, unsigned int> and values of type std::pair<int, CBTNODE>? (CBTNODE is typedef as typedef int CBTNODE)
If it's possible, I would really want to substitute std::pair<std::string, unsigned int> with a typedef-ed INDEX (typedef std::pair<std::string, unsigned int> INDEX)
Any help will be much appreciated!
Z.Zen
This seems to compile and print the right answer (1):
#include <hash_map>
#include <utility>
#include <string>
#include <iostream>
typedef int CBTNODE;
typedef std::pair<std::string, unsigned int> INDEX;
typedef std::pair<int, CBTNODE> Element;
struct pairhash{
size_t operator()(const INDEX &p) const {
return
__gnu_cxx::hash<const char*>()(p.first.c_str()) ^
__gnu_cxx::hash<unsigned int>()(p.second);
}
};
int main() {
__gnu_cxx::hash_map<INDEX, Element, pairhash> x;
INDEX foo("hi", 0);
Element bar(1, 2);
x[foo] = bar;
std::cout << x[foo].first << "\n";
}
Which was a bit tedious. The issue is that __gnu_cxx::hash doesn't provide a specialization for pair, or for that matter for string either. I believe it follows the SGI API here: http://www.sgi.com/tech/stl/hash.html. So pairhash (or something like it) is needed to provide the missing hash function.
I don't blame you for not spotting that, since the compiler error that this caused was a bit, um, non-obvious. And long.
If you can, you're probably better off using boost::unordered_map. SGI's hash_map is an old API, never adopted into the standard, due to be replaced in C++0x, etc, etc.

Copy map values to vector in STL [duplicate]

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