2013-04-28 13 views
7

używam std :: map w taki sposób:C++ std :: map <std :: string, int> uzyskać wartości, których klucz zaczyna się od określonego ciągu znaków

#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

Chciałbym uzyskać wszystkie wartości, których klucz zaczyna się od określonego ciągu (na przykład "Ab"). Mogę łatwo uzyskać iterator początku za pomocą map :: lower_bound. Ale jak mogę uzyskać górną granicę? Czy muszę powtarzać cały zestaw zaczynając od dolnej granicy i sprawdzać każdy klucz, czy nadal zaczyna się od "Ab"?

+2

W tym szczególnym przypadku 'my_map.lower_bound (" Ac ")' wydaje się robić to –

+0

Dlaczego nie otrzymać ograniczenia dla "Ac"? brak liter między b i c. – stardust

+0

Potrzebuję bardziej ogólnego podejścia. Przykład miał tylko opisać problem. Mogę być dowolnym ciągiem znaków, a mapa może zawierać dowolny ciąg znaków. – Dejwi

Odpowiedz

1

znalazłem podobną odpowiedź sprawdzić tę stronę: (map complex find operation)

Kod wywierać:

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 
} 

Wygląda to tak, jakby w tym przykładzie iteracyjne z UPPER_BOUND wstecz do początku szuka specyficzny podciąg

Ten przykład jest nieco inna, ale powinien serwer jako dobry bloku budowlanego

+0

Być może trzeba wspomnieć, że jest to wysoce nieoptymalne rozwiązanie i kolejna baza danych jest w porządku. – 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; 
} 

Kod będzie działał z dowolnym kluczem ciągu.

1

można użyć Boost filter iterator który daje „begin” i „koniec” iterator od zwykłych iteratorów gdy dany predykat (funkcję bool, który mówi, który ceni zawierać)

na przykład:

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(); 
Powiązane problemy