std :: map find_if путаница в стиле условия - PullRequest
11 голосов
/ 08 ноября 2011

Я бы хотел использовать std :: find_if для поиска первого элемента в моей карте, который имеет определенное значение в определенном элементе своей структуры значений.Я немного смущен, хотя.Я думаю, что мне нужно использовать bind1st или bind2nd, но я не уверен, что это правильный путь.

Вот некоторый псевдокод:

struct ValueType { int x, int y, int z };

std::map<int, ValueType> myMap;

... {populate map}

std::map<int, ValueType>::iterator pos = std::find_if(myMap.begin(), myMap.end(), <?>); 

Итак, допустим, что яхотел найти первый элемент карты, где член .x в ValueType был равен некоторому целочисленному значению (которое может изменять каждый вызов).

Что было бы лучшим способом написать функцию или функциюобъект для достижения этого?Я понимаю, что это должен быть унарный предикат, который заставляет меня думать, что мне понадобится bind1st или bind2nd для предоставления целочисленного значения, которое я проверяю, но я не уверен, как это сделать.Прошло слишком много времени с тех пор, как я смотрел на это!>. <</p>

Ответы [ 7 ]

20 голосов
/ 08 ноября 2011

Вы можете использовать лямбда-функцию

int val = ...;
auto it = std::find_if(myMap.begin(), myMap.end(), 
   [val](const std::pair<int, ValueType> & t) -> bool { 
      return t.second.x == val;
   }
);

Но, как подсказывает Кирилл В. Лядвинский, «первый» элемент может оказаться не тем, что вы ожидаете.

18 голосов
/ 08 ноября 2011

Элементы на карте не отсортированы по значению, они отсортированы по ключу. Поэтому фраза «первый элемент» не имеет большого смысла.

Чтобы найти некоторый элемент (не первый), который имеет x, равный некоторому значению, вы можете написать функтор следующим образом:

struct check_x
{
  check_x( int x ) : x_(x) {}
  bool operator()( const std::pair<int, ValueType>& v ) const 
  { 
    return v.second.x == x_; 
  }
private:
  int x_;
};

Затем используйте его следующим образом:

// find any element where x equal to 10
std::find_if( myMap.begin(), myMap.end(), check_x(10) );
3 голосов
/ 08 ноября 2011
struct Pred
{
    Pred(int x) : x_(x) { }
    bool operator()(const std::pair<int, ValueType>& p)
    {
        return (x_ == p.second.x);
    }
private:
    int x_;
};

... = std::find_if(myMap.begin(), myMap.end(), Pred(NUMBER));
1 голос
/ 08 марта 2016

Опираясь на все приведенные выше ответы, я обманываю, используя decltype с семантикой C ++ 11.

auto beg_ = myMap.begin();
auto end_ = myMap.end();
auto it = find_if(beg_, end_,
    [&some_val](decltype(*beg_) & vt) {
        return vt.second == some_val;});
if (end_ != it) {
    auto key_found = (*it).first;
} else {
    // throw error not found.
}
1 голос
/ 08 ноября 2011

с использованием Boost.Bind и Boost.Lambda :

...
#include <boost/bind.hpp>
#include <boost/lambda/lambda.hpp>
...
typedef std::map<int, ValueType> MapType;
...
MapType::iterator pos = std::find_if(myMap.begin(), myMap.end(), 
    boost::bind(&ValueType::y, boost::bind(&MapType::iterator::value_type::second, _1)) == magic_number);
1 голос
/ 08 ноября 2011

Это не имеет ничего общего с std::bind1st или std::bind2nd.Прежде всего, вы должны иметь в виду, что элементы карты являются парами ключ-значение, в вашем случае std::pair<int,ValueType>.Тогда вам просто нужен предикат, который сравнивает член x второго члена пары с определенным значением:

struct XEquals : std::unary_function<std::pair<int,ValueType>,bool>
{
    XEquals(int _x)
        : x(_x) {}
    bool operator()(const std::pair<int,ValueType> &v) const
        { return p.second.x == x; }
    int x;
};
1 голос
/ 08 ноября 2011

Если вы хотите искать также в значениях, то может быть лучше использовать Boost Bimap , чтобы не быть медленным?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...