путаница в стиле std::map find_if condition

#c #stl

#c #stl

Вопрос:

Я хотел бы использовать 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(), <?>); 
  

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

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

Ответ №1:

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

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

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

Ответ №2:

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

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

 struct check_x
{
  check_x( int x ) : x_(x) {}
  bool operator()( const std::pair<int, ValueType>amp; 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) );
  

Комментарии:

1. Поскольку элементы в карте отсортированы по ключу, порядок записей четко определен, и запрос на выполнение условия первым также четко определен.

2. Да, это четко определено. Но порядок не зависит от значения ValueType. Это то, что я пытался сказать.

Ответ №3:

Для ленивых используйте автоматическую лямбду C 17, тогда вам не нужно подробно описывать тип.

 const auto it = std::find_if(myMap.begin(), myMap.end(), [amp;val](const auto amp;it) { 
      return it.second.x == val; // Comparing with the object
   }
);
  

Ответ №4:

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

 auto beg_ = myMap.begin();
auto end_ = myMap.end();
auto it = find_if(beg_, end_,
    [amp;some_val](decltype(*beg_) amp; vt) {
        return vt.second == some_val;});
if (end_ != it) {
    auto key_found = (*it).first;
} else {
    // throw error not found.
}
  

Ответ №5:

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

... = std::find_if(myMap.begin(), myMap.end(), Pred(NUMBER));
  

Ответ №6:

Это не имеет ничего общего с std::bind1st или std::bind2nd . Прежде всего, вы должны иметь в виду, что в вашем случае элементы map являются парами ключ-значение 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> amp;v) const
        { return p.second.x == x; }
    int x;
};
  

Ответ №7:

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

Ответ №8:

используя Boost.Привязать и увеличить.Лямбда-выражение:

 ...
#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(amp;ValueType::y, boost::bind(amp;MapType::iterator::value_type::second, _1)) == magic_number);