8
votes

C ++ stdd :: map obtenir des valeurs dont la clé commence par une chaîne particulière

J'utilise std :: Carte de telle manière: xxx

http: //ideone.com/5ypqmj

J'aimerais avoir toutes les valeurs dont la clé commence par une chaîne particulière (par exemple "AB"). Je peux facilement obtenir le commencement itérateur à l'aide de la carte :: moindre_bound. Mais comment puis-je obtenir une limite supérieure? Dois-je parcourir l'ensemble de l'ensemble à partir de la liaison inférieure et vérifier toutes les touches s'il commence toujours par "AB"?


6 commentaires

Dans ce cas particulier my_map.lower_bound ("AC") semble faire ça


Pourquoi ne pas être lié à "AC"? Pas de lettre entre B et C.


J'ai besoin d'une approche plus générale. L'exemple était juste pour décrire le problème. Je peux être n'importe quel type de chaîne et la carte peut contenir n'importe quel type de chaîne.


@Dejwi aussi longtemps que ce dont vous avez besoin est "qui commence par .." Je pense que cela fonctionnera très bien.


Ok, si je cherchais chaque clé, qui commence par "AZ"? La limite inférieure sera évidemment "AZ" et une limite supérieure?


Le plus approprié ici, je suppose, est de définir une fonction de sorte que, une fois que vous atteignez le dernier caractère de votre éventuelle gamme de caractères, vous devez incrémenter le caractère précédent - de sorte que "AZ" deviendrait "BA" , ou similaire.


3 Réponses :


1
votes

J'ai trouvé une réponse similaire Découvrez cette page: ( MAP Complexe Trouver une opération ) Code EXERT: P>

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
}


1 commentaires

Vous devrez peut-être mentionner qu'il s'agit d'une solution hautement non optimale et une autre datrastructure est en ordre.



1
votes
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)
{
    if(s.length() < key_.length())
        return false;

    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;
}
The code will work with any string key.

0 commentaires

1
votes

Vous pouvez utiliser Boost Filtre Itérateur qui vous donne un "commencement" et un itérateur "fin" d'itérateurs normaux lorsqu'ils donnaient un prédicat (une fonction BOOL qui dit quelles valeurs inclure)

Par exemple: P>

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


0 commentaires