2011-11-08 27 views
8

Me gustaría usar std :: find_if para buscar el primer elemento en mi mapa que tiene un cierto valor en un elemento específico de su estructura de valores. Aunque estoy un poco confundido. Creo que necesito usar bind1st o bind2nd, pero no estoy seguro de que sea el camino correcto.std :: map find_if condición condición confusión

He aquí algunos pseudo-código:

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(), <?>); 

Por lo tanto, digamos que quería encontrar el primer elemento del mapa en el que el miembro de .x del ValueType era equivalente a un determinado valor entero (que puede cambiar cada llamada).

¿Cuál sería la mejor manera de escribir una función o objeto de función para lograr esto? Entiendo que tiene que ser un predicado unario que me haga pensar que necesitaré bind1st o bind2nd para proporcionar el valor entero que estoy buscando, pero no estoy seguro de cómo hacerlo. ¡Ha pasado demasiado tiempo desde que miré esto! >. <

Respuesta

15

Los elementos del mapa no están ordenados por valor, se ordenan según la clave. Entonces la frase "el primer elemento" no tiene mucho sentido.

Para encontrar algunos elemento (no el primero) que tiene x igual a algún valor se puede escribir el functor de la siguiente manera:

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_; 
}; 

A continuación, utilice la siguiente manera:

// find any element where x equal to 10 
std::find_if(myMap.begin(), myMap.end(), check_x(10)); 
+3

Dado que los elementos en el mapa están ordenados por clave, el orden de las entradas está bien definido, y pedir que el primero cumpla una condición también está bien definido. – celtschk

+0

Sí, está bien definido. Pero el orden no depende del valor del ValueType. Eso es lo que estaba tratando de decir. –

+0

Gracias, exactamente lo que necesitaba :) –

3
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

Si desea buscar también en valores, ¿puede ser mejor usar Boost Bimap para no demorar?

11

Se puede utilizar una función lambda

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

Pero a medida que Kirill V. Lyadvinsky respuesta sugiere el elemento "primero" puede que no sea el esperado.

1

Esto no tiene nada que ver con std::bind1st o std::bind2nd. En primer lugar, debe tener en cuenta que los elementos de un mapa son pares clave-valor, en su caso std::pair<int,ValueType>. Entonces sólo tiene un predicado que compara el miembro de x del segundo miembro de un par yuch contra un valor específico:

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

usando Boost.Bind y 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

Sobre la base de todas las respuestas anteriores hago trampa usando decltype con semántica 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. 
}