Using find_if on map to find by value
I have a class which has a map. I need to find iterator in map by searching for a particualar value, instad of开发者_如何学编程 the key. Using a member function predicate IsValueFound, am trying this.
class A
{
public:
void findVal();
private:
int state;
map<int, int> exmap;
bool IsValueFound(pair<int key, int val> itr)
{
return state == itr.second;
}
};
void A::findVal
{
itr = find_if(exmap.begin, exmap.end, mem_fun1_ref(&A::IsValueFound));
}
Iam getting compilation errors. Iam not sure whats the syntax for these function adaptors. Please help.
EDIT: Sorry. Please neglect the compilation errors arising other than from finf_if stmt. I need to get find_if stmt corrected first. Also the code doesn't have boost :(
Its slightly easier to convert the object A into a functor:
But there were other problems with your code (see below):
#include <map>
#include <memory>
#include <functional>
#include <algorithm>
using namespace std;
class A {
public:
void findVal();
private:
int state;
map<int, int> exmap;
// Changed the function IsValueFound() to operator()
// This makes the whole object behave like a function.
// Its a lot easier then getting member functions and binding
// the this reference.
bool operator()(map<int,int>::value_type const& itr) const
// ^^^^^^^^^^^^^^^^^
// std::pair<int,int> is not the type held in the map
// so you are not going to bind against it using a pair.
{
return state == itr.second;
}
};
void A::findVal()
{
// You did not specify a type
// for the iterator in your code.
std::map<int,int>::iterator itr1 = find_if(exmap.begin(), exmap.end(), *this);
// ^^^^^^ ^^^^^^
// begin() and end() are methods.
// Just pass the `this` object as the the third parameter it will act as a function now.
}
Edit: there's obviously an error in my answer, mem_fun1_ref(&A::IsValueFound)
doesn't work as a predicate for std::find_if
. I'm working on correcting that.
you forgot parenthesis with exmap.begin
and exmap.end
.
I think if you had read the compilation error report, it would have told seomthing about it.
I would write that this way:
typedef map<int, int>::const_iterator MyIterator
void A::findVal()
{
const MyIterator itrBegin = exmap.begin();
const MyIterator itrEnd = exmap.end();
MyIterator itrFound = find_if( itrBegin ,
itrEnd ,
mem_fun1_ref(&A::IsValueFound));
}
but I havent't tried mem_fun1_ref(&A::IsValueFound)
to compile. and I'm not used to using mem_fun1_ref
, I always redefine my own functor with their operator()
.
If you do not want to use Boost Bimap you can create a so-called functor, an object that overload the function call operator ()
. In this piece of code:
class A {
public:
bool findVal(int s);
private:
map<int, int> exmap;
struct IsValueFound {
int state;
IsValueFound(int _state) : state(_state) {};
bool operator()(const pair<int, int>& itr) {
return state == itr.second;
}
};
};
bool A::findVal(int x) {
return (find_if(exmap.begin(), exmap.end(), A::IsValueFound(x)) != exmap.end());
}
As for the compilation errors, you're declaring your iterator wrong in IsValueFound's argument list, for one. It should be:
map<int, int>::iterator itr
Then in A::findVal itr is not declared at all.
Having said that, scanning a map for values is not a good idea if you need to do this often. You should consider some other internal representation for your data.
mem_fun_ref
takes your one argument function
bool IsValueFound(pair<int, int> itr)
and turns it into a two argument functor:
bool functor(A& this, pair<int, int> itr)
.
where the reference used as the first parameter is used to generate the this
pointer to call the member function IsValueFound
.
You probably don't want anything mem_fun_ref
related here -- the binders will work just fine:
std::find_if(exmap.begin, exmap.end, std::bind2nd(std::equal_to<int>(), state));
Just realized that won't work for a map iterator... I would probably just write an explicit loop at this point.
There are a few syntax errors you've got here too but @martona already touched on them so I won't beat a dead horse :)
you actually use your map as a bi-directional map
, so you may find boost's Boost Multi-index Containers useful. They have a specific example of implementing a bi-directional map.
Just use Boost Bimap.
精彩评论