Jump to content

  • Log In with Google      Sign In   
  • Create Account


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.

  • You cannot reply to this topic
3 replies to this topic

#1 lride   Members   -  Reputation: 633

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.

Sponsor:

#2 fastcall22   Crossbones+   -  Reputation: 3969

Like
2Likes
Like

Posted 21 January 2013 - 10:07 PM

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

WW91J3ZlIGdvdCBhIHNlY3JldCBib251cyBwb2ludCE=


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

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.

[Fly with me on Twitter] [Google+] [My broken website]

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]

Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal


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

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.

[Fly with me on Twitter] [Google+] [My broken website]

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]

Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal





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