Векторы, структуры и std::find

Опять я с векторами. Надеюсь, я не слишком раздражаю. У меня есть такая структура:

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

Поэтому я создал вектор:

std::vector<monster> monsters;

Но теперь я не знаю, как искать по вектору. Я хочу найти идентификатор монстра внутри вектора.

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

Но очевидно, что это не работает. Я хочу перебирать только элемент .id структуры, и я не знаю, как это сделать. Помощь приветствуется. Спасибо !


person Ahmed    schedule 26.02.2009    source источник
comment
Отличный вопрос, именно то, что мне было нужно. Совершенно не раздражает :)   -  person tomereli    schedule 05.04.2018


Ответы (7)


std::find_if:

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

Или напишите свой собственный объект функции, если у вас нет повышения. Будет выглядеть так

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));
person Johannes Schaub - litb    schedule 26.02.2009
comment
используя ускорение, отлично! - person H'H; 14.11.2014
comment
Интересно, если у меня есть {int, int}, могу ли я преобразовать его в long и использовать обычный поиск? - person Tomáš Zato - Reinstate Monica; 20.10.2015
comment
Что означает бот в bot.monsters.begin()? - person Semjon Mössinger; 07.01.2016
comment
Что такое тип данных, если это ?? - person nathan; 14.10.2016
comment
хорошо, что вы привели пример без буста - мы никогда не используем буст во встраиваемых системах, он огромен. Я просто не понял, почему вы унаследовали объект функтора от std::unary_function - похоже, он будет работать в любом случае, не так ли? ценю ваш ответ. - person tomereli; 05.04.2018
comment
@Hiyper — тип будет std::vector‹monster›::iterator. Или вы можете использовать auto it = std::find_if... если вы используете С++ 11 - person tomereli; 05.04.2018
comment
@tomereli IIRC без него не будет работать в С++ 03, но я думаю, что будет в С++ 11, который может сам определить тип возвращаемого значения, используя decltype. - person Johannes Schaub - litb; 06.04.2018
comment
@SemjonMössinger Это не было указано явно, но bot должна быть структурой, содержащей следующий вектор структур: std::vector<monster> monsters; - person Adam Erickson; 07.06.2018
comment
unary_function устарела в C++11 и удалена в C++17. - person Darkproduct; 19.10.2018

как насчет:

std::find_if(monsters.begin(), 
             monsters.end(), 
             [&cm = currentMonster]
             (const monster& m) -> bool { return cm == m; }); 
person Community    schedule 08.01.2010
comment
Может ли кто-нибудь, кто видит это, рассказать мне, что он делает? В частности, [&cm = currentMonster](const monster& m) -> bool { return cm == m; }); - person 2kreate; 29.11.2014
comment
В этом примере используется лямбда-функция, которая зависит от C++11. [&cm = currentMonster] связывает переменную currentMonster из области вызова с локальной ссылкой в ​​лямбда-выражении, называемой cm. Затем (const monster& m) -> bool определяет подпись лямбды, принимая один входной параметр, m, и возвращая bool. Телом лямбда-функции является { return cm == m; }, возвращающее true, если cm и m сравниваются как равные. - person Derek T. Jones; 25.06.2015
comment
Наконец-то я знаю, как правильно привязывать локальные переменные к лямбда-выражениям. - person Tomáš Zato - Reinstate Monica; 20.10.2015
comment
обязательна ли часть -› bool? он будет компилироваться в любом случае, не так ли? - person tomereli; 05.04.2018
comment
Для { return cm == m; } в конце требуется operator==, определенный в структуре (см. ответ @dirkgently). Без operator== измените оператор return на { return cm.id == m.id; } - person Tzunghsing David Wong; 27.03.2019

Вам нужно написать свой собственный поисковый предикат:

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));
person Evgeny Lazin    schedule 26.02.2009
comment
Хороший ответ, но в конструкторе опечатка. Это должно быть ':', а не ';' - person Martin Sherburn; 24.08.2012
comment
Помимо написания собственного предиката поиска, вам нужно использовать std::find_if вместо std::find. - person Christian Rau; 25.08.2012

Взгляните на шаблон std::find, особенно на третий параметр:

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

Что такое EqualityComparable? Опять же из документации:

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

Теперь ваш тип монстра должен определить такой оператор. Если вы этого не сделаете, компилятор сгенерирует его для вас (а также ctor и dtor по умолчанию), который делает что-то вроде memcmp, что не работает в вашем случае. Итак, чтобы использовать std::find, сначала определите функцию/функтор компаратора, которую алгоритм может использовать для соответствия вашему currentMonster, то есть что-то вроде:

 struct monster {
  // members
  bool operator==(const monster& l, const monster& r) const
  {
     return l.id == r.id;
  }
 };
person dirkgently    schedule 26.02.2009
comment
Это работает? У меня не получилось, потому что определение оператора внутри структуры может иметь только 1 вход - person Kyle Heuton; 15.04.2013
comment
Та же проблема, что и у Snoozer. -1, пожалуйста, завершите ответ. - person Tomáš Zato - Reinstate Monica; 20.10.2015
comment
концепция правильная. это работает для меня: bool operator==(const monster& r) const { return id == r.id; } - person Tzunghsing David Wong; 27.03.2019

или поставить монстров на карту вместо вектора

или если они должны быть в векторе, создайте индексную карту, т.е. карту ID в векторный индекс

person pm100    schedule 08.01.2010

Это полный образец, основанный на ответе Йоханнеса Шауба (ускоренная версия).

#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;
}
person Semjon Mössinger    schedule 07.01.2016

Вы можете написать функцию, как показано ниже:

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

Он возвращает указатель на сохраненный узел, если он найден в векторе, в противном случае возвращает NULL.

Обратите внимание, что return it; не будет работать напрямую.

person Aditya Sharma    schedule 18.09.2019