• Create Account

Need scary sound effects or creepy audio loops for your next horror-themed game? Check out Highscore Vol.3 - The Horror Edition in our marketplace. 50 sounds and 10 loops for only \$9.99!

# Interchangeable key-value map

Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

3 replies to this topic

### #1lride  Members   -  Reputation: 625

Like
0Likes
Like

Posted 21 January 2013 - 09:54 PM

WIth std::map<Key, Value>, I can get a value if I have a key, but not vice versa.

I need a map that can do both. Is there one that can do this?

An invisible text.

### #2fastcall22  Crossbones+   -  Reputation: 2418

Like
2Likes
Like

Posted 21 January 2013 - 10:07 PM

boost::bimap. Not currently aware if there are any C++11 alternatives...

### #3Servant of the Lord  Crossbones+   -  Reputation: 12492

Like
2Likes
Like

Posted 21 January 2013 - 10:53 PM

You could probably do a std::vector<std::pair<Key1, Key2>>, and use std::find_if(), with the predicate checking only first or only second of the pair element, returning a match for either one. It wouldn't be sorted for rapid searches, though.

But now that I think about it, you could just do std::find_if() on a std::map when you need by-value lookups, if you don't need it frequently.

You could either use a lambda to do your search, if you use C++11, or you could use a functor like this:

template<typename KeyType, typename ValueType>
class SearchByValue
{
public:
SearchByValue(ValueType value) : value(value)
{	}

bool operator()(const std::pair<KeyType, ValueType> &pair)
{
//Return true if the pair's value matches our value.
return (pair.second == this->value);
}

private:
ValueType value;
};

int main(int argc, char *argv[])
{
typedef std::map<std::string, int>::iterator MyMapIterator;

std::map<std::string, int> myMap;

myMap["One"] = 1;
myMap["Two"] = 2;
myMap["Three"] = 3;

MyMapIterator it = std::find_if(myMap.begin(), myMap.end(), SearchByValue<std::string, int>(2));

if(it == myMap.end())
{
std::cout << "Couldn't find it!" << std::endl;
}
else
{
std::cout << "The returned key-value pair is: (\"" << it->first << "\", " << it->second << ")" << std::endl;
}

return 0;
}

Result: The returned key-value pair is: ("Two", 2)

The templated functor I gave should work for most maps.

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.

All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.                                                                                                                                                       [Need free cloud storage? I personally like DropBox]

### #4Servant of the Lord  Crossbones+   -  Reputation: 12492

Like
1Likes
Like

Posted 21 January 2013 - 11:25 PM

Here's a function wrapping it up every nicer (still avoiding C++11 lambda and auto, just incase you can't use them):

/*
A functor for doing a reverse value-to-key lookup on a map.

Example:
typedef std::map<std::string, int>::iterator MyMapIterator;

std::map<std::string, int> myMap;

myMap["One"] = 1;
myMap["Two"] = 2;
myMap["Three"] = 3;

MyMapIterator it = std::find_if(myMap.begin(), myMap.end(), SearchByValue<std::string, int>(2));
*/
template<typename KeyType, typename ValueType>
class SearchByValue
{
public:
SearchByValue(const ValueType &value) : value(value)
{	}

bool operator()(const std::pair<KeyType, ValueType> &pair)
{
//Return true if the pair's value matches our value.
return (pair.second == this->value);
}

private:
ValueType value;
};

//Searches a map by value to find the key.
//Example usage:
//		std::string key = SearchMapByValue(map, 357 /* value */, "fallback");
template<typename MapType>
const typename MapType::key_type &SearchMapByValue(const MapType &map, const typename MapType::mapped_type &valueToFind,
const typename MapType::key_type &fallback = typename MapType::key_type())
{
typename MapType::const_iterator it = std::find_if(map.begin(), map.end(), SearchByValue<typename MapType::key_type, typename MapType::mapped_type>(valueToFind));

if(it == map.end())
return fallback;

return it->first;
}

And you can use it as a simple function call, and all the templated types are automaticly detected by the map passed in:

std::map<std::string, int> myMap;

myMap["One"] = 1;
myMap["Two"] = 2;
myMap["Three"] = 3;

std::cout << "The key is: \"" << SearchMapByValue(myMap, 2) << "\"" << std::endl;


Result: The key is: "Two"

Put in a stand-alone header file, all you have to do is call SearchMapByValue(myMap, 2) or SearchMapByValue(myMap, 2, "fallback") and it'll "just work" with any variable type in a map that handles equality. (Searching for floats wouldn't be a good idea, but even some complex classes that have operator == would be fine)

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.

All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.                                                                                                                                                       [Need free cloud storage? I personally like DropBox]

Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

PARTNERS