2011-11-08 11 views
8

Vorrei utilizzare std :: find_if per cercare il primo elemento nella mia mappa che ha un determinato valore in un elemento specifico della sua struttura di valori. Sono un po 'confuso però. Penso di aver bisogno di usare bind1st o bind2nd, ma non sono sicuro che sia la strada giusta da percorrere.std :: map find_if condition confusion style

Ecco alcuni pseudo-codice:

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

Quindi, diciamo che volevo trovare il primo elemento della mappa in cui il membro .x del ValueType è stato pari a un certo valore intero (che può cambia ogni chiamata).

Quale sarebbe il modo migliore per scrivere una funzione o un oggetto funzione per ottenere ciò? Capisco che deve essere un predicato unario che mi fa pensare che avrò bisogno di bind1st o bind2nd per fornire il valore intero che sto verificando, ma non sono sicuro di come farlo. È passato troppo tempo da quando ho guardato questa roba! >. <

risposta

15

Gli elementi nella mappa non sono ordinati per valore, sono ordinati in base alla chiave. Quindi la frase "il primo elemento" non ha molto senso.

Per trovare alcuni elemento (non il primo) che ha x uguale a un valore che si può scrivere la funtore come segue:

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

Quindi utilizzare come segue:

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

Poiché gli elementi nella mappa sono ordinati per chiave, l'ordine delle voci è ben definito e quindi il primo che soddisfa una condizione è anche ben definito. – celtschk

+0

Sì, è ben definito. Ma l'ordine non dipende dal valore di ValueType. Questo è quello che stavo cercando di dire. –

+0

Grazie, esattamente quello di cui avevo bisogno :) –

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

Se si desidera cercare anche nei valori, potrebbe essere preferibile utilizzare Boost Bimap per non rallentare?

11

è possibile utilizzare una funzione 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; 
    } 
); 

Ma, come suggerisce Kirill V. Lyadvinsky risposta l'elemento "prima" non può essere quello che vi aspettate.

1

Questo non ha nulla a che fare con std::bind1st o std::bind2nd. Prima di tutto, devi tenere presente che gli elementi di una mappa sono coppie chiave-valore, nel tuo caso std::pair<int,ValueType>. Poi basta un predicato che confronta il membro x del secondo membro della yuch una coppia contro un valore specifico:

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

utilizzando Boost.Bind e 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

Sulla base di tutte le risposte precedenti, imbroglio usando decltype con la semantica 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. 
}