41

Again me with vectors. I hope I'm not too annoying. I have a struct like this :

struct monster 
{
    DWORD id;
    int x;
    int y;
    int distance;
    int HP;
};

So I created a vector :

std::vector<monster> monsters;

But now I don't know how to search through the vector. I want to find an ID of the monster inside the vector.

DWORD monster = 0xFFFAAA;
it = std::find(bot.monsters.begin(), bot.monsters.end(), currentMonster);

But obviously it doesn't work. I want to iterate only through the .id element of the struct, and I don't know how to do that. Help is greatly appreciated. Thanks !

Evgeny Lazin
  • 9,193
  • 6
  • 47
  • 83
liliumdev
  • 1,159
  • 4
  • 13
  • 25

7 Answers7

42

std::find_if:

it = std::find_if(bot.monsters.begin(), bot.monsters.end(), 
        boost::bind(&monster::id, _1) == currentMonster);

Or write your own function object if you don't have boost. Would look like this

struct find_id : std::unary_function<monster, bool> {
    DWORD id;
    find_id(DWORD id):id(id) { }
    bool operator()(monster const& m) const {
        return m.id == id;
    }
};

it = std::find_if(bot.monsters.begin(), bot.monsters.end(), 
         find_id(currentMonster));
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
26

how about:

std::find_if(monsters.begin(), 
             monsters.end(), 
             [&cm = currentMonster]
             (const monster& m) -> bool { return cm == m; }); 
  • 2
    Could someone who sees this walk me through what it's doing? Specifically the [&cm = currentMonster](const monster& m) -> bool { return cm == m; }); – 2kreate Nov 29 '14 at 19:57
  • 7
    This example uses a lambda function, which depends on C++11. `[&cm = currentMonster]` binds the variable `currentMonster` from the calling scope to a local reference in the lambda, called `cm`. Then `(const monster& m) -> bool` defines the signature of the lambda, taking one input parameter, `m`, and returning `bool`. The body of the lambda function is `{ return cm == m; }`, returning true if `cm` and `m` compare as equal. – Derek T. Jones Jun 25 '15 at 13:56
  • 1
    Finally I know how to properly bind local variables to lambdas. – Tomáš Zato Oct 20 '15 at 14:43
  • is the -> bool part necessary? it would compile either way, won't it? – tomereli Apr 05 '18 at 08:24
  • 1
    The `{ return cm == m; }` at the end requires an `operator==` defined in the struct (see @dirkgently answer), Without the `operator==`, change the return statement to `{ return cm.id == m.id; }` – Tzunghsing David Wong Mar 27 '19 at 01:18
21

You need to write your own search predicate:

struct find_monster
{
    DWORD id;
    find_monster(DWORD id) : id(id) {}
    bool operator () ( const monster& m ) const
    {
        return m.id == id;
    }
};

it = std::find_if( monsters.begin(), monsters.end(), find_monster(monsterID));
Evgeny Lazin
  • 9,193
  • 6
  • 47
  • 83
9

Take a look at the std::find template, the third parameter especially:

template<class InputIterator, class EqualityComparable>
InputIterator find(InputIterator first, InputIterator last,
               const EqualityComparable& value);

What is this EqualityComparable? Again from the documentation:

A type is EqualityComparable if objects of that type can be 
compared for equality using operator==, and if operator== is 
an equivalence relation. 

Now, your type monster needs to define such an operator. If you don't the compiler generates one for you (as also the default ctor and the dtor) which does a memcmp sort of thing which doesn't work in your case. So, to use std::find first define a comparator function/functor that the algorithm can use to match your currentMonster i.e. something along the lines of:

 struct monster {
  // members
  bool operator==(const monster& l, const monster& r) const
  {
     return l.id == r.id;
  }
 };
dirkgently
  • 108,024
  • 16
  • 131
  • 187
1

or put the monsters in a map instead of a vector

or if they must be in a vector create an index map ie map of ID to vector index

pm100
  • 48,078
  • 23
  • 82
  • 145
0

This is a complete sample based on the answer of Johannes Schaub (boost version).

#include <algorithm>
#include <boost/bind.hpp>

struct monster 
{
    DWORD id;
    int x;
    int y;
    int distance;
    int HP;
};

int main ()
{
    std::vector<monster> monsters;

    monster newMonster;
    newMonster.id    = 1;
    newMonster.x     = 10;
    monsters.push_back ( newMonster );

    newMonster.id    = 2;
    newMonster.x     = 20;
    monsters.push_back ( newMonster );

    newMonster.id    = 2;
    newMonster.x     = 30;
    monsters.push_back ( newMonster );

    DWORD monsterId = 2;

    std::vector< monster >::iterator it = std::find_if ( monsters.begin (), monsters.end (), 
        boost::bind ( &monster::id, _1 ) == monsterId );

    return 0;
}
Semjon Mössinger
  • 1,798
  • 3
  • 22
  • 32
0

You can write a function as below:

monster* findMonster(DWORD currentMonster) {
    for (auto it = bot.monsters.begin(); it != bot.monsters.end(); it++) {
        if (it->id == currentMonster) {
            return &(*it);
        }
    }
    return NULL;
}

It returns a pointer to the stored node if it's found in the vector, otherwise returns NULL.

Please note that return it; won't work directly.