2013-04-28 9 views
7

sto usando std :: map in modo tale:C++ std :: map <std :: string, int> valori ottenere che cominciano chiave con una particolare stringa

#include <map> 
#include <string> 
#include <iostream> 

using namespace std; 

int main(int argc, char* argv[]) 
{ 
    map<string, int> my_map; 

    my_map.insert(pair<string, int>("Ab", 1)); 
    my_map.insert(pair<string, int>("Abb", 2)); 
    my_map.insert(pair<string, int>("Abc", 3)); 
    my_map.insert(pair<string, int>("Abd", 4)); 
    my_map.insert(pair<string, int>("Ac", 5)); 
    my_map.insert(pair<string, int>("Ad", 5)); 

    cout<<my_map.lower_bound("Ab")->second<<endl; 
    cout<<my_map.upper_bound("Ab")->second<<endl; 
    return 0; 
} 

http://ideone.com/5YPQmj

Mi piacerebbe ottenere tutti i valori la cui chiave inizia con una stringa particolare (ad esempio "Ab"). Posso facilmente ottenere l'iteratore di inizio usando map :: lower_bound. Ma come posso ottenere un limite superiore? Devo ripetere l'intero set partendo dal limite inferiore e controllare ogni tasto se inizia ancora con "Ab"?

+2

In questo caso particolare 'my_map.lower_bound (" Ac ")' sembra farlo –

+0

Perché non ottenere il limite per "Ac"? nessuna lettera tra b e c. – stardust

+0

Ho bisogno di un approccio più generale. L'esempio era solo per descrivere il problema. Posso essere qualsiasi tipo di stringa e la mappa può contenere qualsiasi tipo di stringa. – Dejwi

risposta

1

ho trovato una risposta simile Guarda cosa: (map complex find operation)

Codice Exert:

template<typename Map> typename Map::const_iterator 
find_prefix(Map const& map, typename Map::key_type const& key) 
{ 
    typename Map::const_iterator it = map.upper_bound(key); 
    while (it != map.begin()) 
    { 
     --it; 
     if(key.substr(0, it->first.size()) == it->first) 
      return it; 
    } 

    return map.end(); // map contains no prefix 
} 

Sembra come se in questo esempio di eseguire iterazioni dal superiore limite a ritroso fino all'inizio cercando il stringa specifica

Questo esempio è un po 'diverso, ma dovrebbe server come un buon blocco di costruzione

+0

Potrebbe essere necessario menzionare che si tratta di una soluzione altamente non ottimale e un altro datastructure è in ordine. – sehe

1
class BeginWithKey 
{ 
public: 
    BeginWithKey(const string key); 
    bool operator()(const string& s,const int x); 
private: 
    const string& key_; 
}; 

BeginWithKey::BeginWithKey(const string key):key_(key) 
{ 
} 

bool BeginWithKey::operator()(const string& s, const int& rh) 
{ 
    bool begin = true; 

    for(int i = 0; i < key_.size() && begin; ++i) 
     begin = (s[i] == key_[i]); 
    return !begin; 
} 

int main() 
{ 
    //your code 

    //copying the map object 
    map<string, int> copy = my_map; 

    //removing the strings not beginning with abc 
    BeginWithKey func("abc"); 
    remove_if(copy.begin(), copy.end(), func); 

    return 0; 
} 

Il codice funzionerà con qualsiasi chiave di stringa.

1

è possibile utilizzare Boost filter iterator che vi darà un "begin" e di un "fine" iteratore da iteratori normali quando hanno dato un predicato (una funzione bool che dice i valori da includere)

Ad esempio:

template <class Predicate> 
boost::filter_iterator<Predicate, map<string,int>::const_iterator> begin(Predicate predicate) const 
{ 
    return boost::make_filter_iterator(predicate, my_map.begin(), my_map.end()); 
} 
template <class Predicate> 
boost::filter_iterator<Predicate, map<string,int>::const_iterator> end(Predicate predicate) const 
{ 
    return boost::make_filter_iterator(predicate, my_map.end(), my_map.end()); 
} 

struct isMatch 
{ 
    isMatch(const std::string prefix) {m_prefix = prefix;}; 
    bool operator()(std::string value) 
    { 
     return value.find_first_of(m_prefix) == 0; 
    }; 
    std::string m_prefix; 
}; 

//using: 
isMatch startWithAb("Ab"); 
auto myBegin = boost::filter_iterator<startWithAb> begin(); 
auto myEnd = boost::filter_iterator<startWithAb> end(); 
Problemi correlati