7

I'm sure I'm making this harder than it needs to be.

I have a vector...

vector<Joints> mJointsVector;

...comprised of structs patterned after the following:

struct Joints
{
    string name;

    float origUpperLimit;
    float origLowerLimit;   
};

I'm trying to search mJointsVector with "std::find" to locate an individual joint by its string name - no luck so far, but the examples from the following have helped, at least conceptually:

Vectors, structs and std::find

Can anyone point me further in the right direction?

Community
  • 1
  • 1
Monte Hurd
  • 4,349
  • 5
  • 30
  • 35
  • 1
    While the answers below are well and good, your usage sounds like you should be using a `map` instead, from `string` to `Joints`. This will also improve your look-up times. – GManNickG Jan 08 '10 at 07:16
  • I think you're probably right - I'll have to look into this later. – Monte Hurd Jan 08 '10 at 08:49
  • Wow, maps and multimaps *are* great! Especially with *for_each* using function objects instead of loops! http://www.codeproject.com/KB/stl/replace_for_for_each.aspx?display=Print So useful to be able to "reuse" loop code this way. – Monte Hurd Feb 09 '10 at 08:01

6 Answers6

16

A straight-forward-approach:

struct FindByName {
    const std::string name;
    FindByName(const std::string& name) : name(name) {}
    bool operator()(const Joints& j) const { 
        return j.name == name; 
    }
};

std::vector<Joints>::iterator it = std::find_if(m_jointsVector.begin(),
                                                m_jointsVector.end(),
                                                FindByName("foo"));

if(it != m_jointsVector.end()) {
    // ...
}

Alternatively you might want to look into something like Boost.Bind to reduce the amount of code.

Georg Fritzsche
  • 97,545
  • 26
  • 194
  • 236
  • 2
    while this works, I think the operator() of a function object should always be const, just for flexibility. if one day you have a range of const Joints, the function object still works. – vividos Jan 08 '10 at 07:46
  • This only seems to work if I change "bool operator(" to "bool operator()(". Is this correct? I'm overwhelmed by how many ways there are to do this! – Monte Hurd Jan 08 '10 at 08:14
  • Oops, i missed the first parentheses - fixed. – Georg Fritzsche Jan 08 '10 at 08:18
  • 1
    @vividos: It already works with `const Joints` - i agree on the constness though. – Georg Fritzsche Jan 08 '10 at 09:34
5

how about:

std::string name = "xxx";

std::find_if(mJointsVector.begin(), 
             mJointsVector.end(), 
             [&s = name](const Joints& j) -> bool { return s == j.name; }); 
  • Uh, what? This isn't yet supported :P (Even then, I think this is wrong.) – GManNickG Jan 08 '10 at 07:20
  • 7
    Its not wrong, its correct and in a couple of years time, this answer will be seen as being "more" correct when compared to the others. –  Jan 08 '10 at 08:14
  • Darid, what do you mean? Why is this more correct? Not challenging you - I'm totally clueless actually - and curious. – Monte Hurd Jan 08 '10 at 08:20
  • @darid: Don't edit your answer *then* refute my statement! :P That's like virtual straw-man. It was wrong, but now it's definitely good. :] – GManNickG Jan 08 '10 at 08:22
  • 1
    @Monte: The other answers are what you need to do today. This feature, called "lambdas", are basically in-place functions. In essence, they create unnamed functors, similar to the other answers. But this keeps the logic close to the calling site, and is arguably more readible. – GManNickG Jan 08 '10 at 08:23
  • Though the anonymous function is a good idea, shouldn't you use `find_if`? – xtofl Jan 08 '10 at 08:25
  • It is supported by intel compilers (lambdas, I have not tested this one) and seems wrong: the argument should be `const Joint&` and the comparison should probably be `name != s.name`, and it should be `find_if` – David Rodríguez - dribeas Jan 08 '10 at 08:25
  • 2
    @GMan: jeeez you're too quick for me, i was hoping to go under the radar with that edit :> –  Jan 08 '10 at 08:26
  • 3
    @dribeas: (1)The type is Joints not Joint (2) The comparison is correct - please read the code (3) Generally this is the direction C++ is going, people should start using these features instead of slopping around with vc6, vc8, vc9 gen compilers. –  Jan 08 '10 at 08:29
  • So lambda support is not quite ubiquitous? Can anyone tell me if they're safe to use with OS X 10.6 or iPhone projects? – Monte Hurd Jan 08 '10 at 08:38
  • I missed your edited code while reading some of the other answers, so you are right in both the Joints and the comparison being correct now. Still it should be `find_if` instead of `find` and I am not sure that the syntax you are using for capturing the `name` variable is true. Maybe: `std::find_if(...,[&name](const Joints& j)->...)`? – David Rodríguez - dribeas Jan 08 '10 at 08:42
  • @Monte: its a feature that will be in the next C++ standard that is not out yet. Current gcc versions support it when setting a flag, Visual Studio 2010 will also support them. – Georg Fritzsche Jan 08 '10 at 08:42
  • @Monte: if you can use g++ 4.5 or later you can try, but g++ 4.4 and before did not have lambda support. And then again, I would not try the latest addition into the compiler for production code until some time and testing has been performed. – David Rodríguez - dribeas Jan 08 '10 at 08:45
1

You should be able to add a equals operator do your struct

struct Joints
{
    std::string name;

    bool operator==(const std::string & str) { return name == str; }
};

Then you can search using find.

Jason T.
  • 362
  • 2
  • 11
  • The equality operator should be reserved for use to test if two objects of the same type are equivalent. Only very rarely should you use it to compare with other types. – Martin York Jan 08 '10 at 07:31
  • Mind explaining why or cite a source that does? – Jason T. Jan 08 '10 at 08:02
  • This simple short answer has many shortcommings: you should prefer free function operators over member function operators (symmetry with respect to types in some operations), if you overload == you should also overload !=, and finally as Martin pointed, when overloading an operator you should not change the semantics. The operator symbol implies some semantics to the reader, if those semantics are broken the possibility of errors in user code increases. Who could think that `a==b` would yield true for different objects? – David Rodríguez - dribeas Jan 08 '10 at 08:23
1
#include <boost/bind.hpp>

std::vector<Joints>::iterator it;

it = std::find_if(mJointsVector.begin(),
                  mJointsVector.end(),
                  boost::bind(&Joints::name, _1) == name_to_find);
Fred
  • 1,448
  • 1
  • 9
  • 4
0
bool
operator == (const Joints& joints, const std::string& name) {
    return joints.name == name;
}

std::find(mJointsVector.begin(), mJointsVector.end(), std::string("foo"));
Andreas Brinck
  • 51,293
  • 14
  • 84
  • 114
0
struct Compare: public unary_function <const string&>
{
     public:
            Compare(string _findString):mfindString(_findString){}
            bool operator () (string _currString)
            {
                return _currString == mfindString ;
            }
     private:
            string mfindString ;
}

std::find_if(mJointsVector.begin(), mJointsVector.end(), Compare("urstring")) ;
mukeshkumar
  • 2,698
  • 3
  • 19
  • 20
  • You never declared `_currString` or `_findString` and your inheritance is wrong (precise the template parameters) – Matthieu M. Jan 08 '10 at 17:37