Подтвердить что ты не робот

Std:: map частичное совпадение ключа

У меня есть std:: map, и я хочу искать ключ, используя подстроку. Для примера

#include <iostream>
#include <map>
#include <string>
using namespace std;

typedef std::map<std::string, std::string> TStrStrMap;
typedef std::pair<std::string, std::string> TStrStrPair;

int main(int argc, char *argv[])
{
        TStrStrMap tMap;

        tMap.insert(TStrStrPair("John", "AA"));
        tMap.insert(TStrStrPair("Mary", "BBB"));
        tMap.insert(TStrStrPair("Mother", "A"));
        tMap.insert(TStrStrPair("Marlon", "C"));


        return 0;
}

Я хочу найти позицию, которая содержит подстроку "Marl", а не "Marlon". Является ли это возможным? Как?

РЕДАКТИРОВАТЬ: нет библиотек boost!

4b9b3361

Ответ 1

Вы не можете эффективно искать подстроку, но можете использовать префикс:

#include <iostream>
#include <map>
#include <string>
#include <algorithm>
using namespace std;

typedef map<string, string> TStrStrMap;
typedef pair<string, string> TStrStrPair;

TStrStrMap::const_iterator FindPrefix(const TStrStrMap& map, const string& search_for) {
    TStrStrMap::const_iterator i = map.lower_bound(search_for);
    if (i != map.end()) {
        const string& key = i->first;
        if (key.compare(0, search_for.size(), search_for) == 0) // Really a prefix?
            return i;
    }
    return map.end();
}

void Test(const TStrStrMap& map, const string& search_for) {
    cout << search_for;
    auto i = FindPrefix(map, search_for);
    if (i != map.end())
        cout << '\t' << i->first << ", " << i->second;
    cout << endl;
}

int main(int argc, char *argv[])
{
    TStrStrMap tMap;

    tMap.insert(TStrStrPair("John", "AA"));
    tMap.insert(TStrStrPair("Mary", "BBB"));
    tMap.insert(TStrStrPair("Mother", "A"));
    tMap.insert(TStrStrPair("Marlon", "C"));

    Test(tMap, "Marl");
    Test(tMap, "Mo");
    Test(tMap, "ther");
    Test(tMap, "Mad");
    Test(tMap, "Mom");
    Test(tMap, "Perr");
    Test(tMap, "Jo");

    return 0;
}

Отпечатки:

Marl    Marlon, C
Mo      Mother, A
ther
Mad
Mom
Perr
Jo      John, AA

Ответ 2

Когда ваша подстрока является префиксом, как в вашем примере, вы можете использовать lower_bound для поиска "Marl".

    map<string,string>::const_iterator m = tMap.lower_bound("Marl");
    cerr << (*m).second << endl;

Это не работает для подстрок без префикса: в общем случае поиск карты не сильно отличается от поиска в других контейнерах.

Ответ 3

Чтобы найти подстроку ключа на карте, у вас нет выбора, кроме как использовать новую карту по типу особого типа или для поиска вашей карты в O (n). std::map использует (по умолчанию) operator<() для упорядочения ключей и поиска, а функция сравнения для std::string - это простой лексикографический счёт.

Если вы создаете новую карту по специальному типу ключа, который имеет operator<() compare на основе подстроки, обратите внимание, что это также повлияет на решение о том, будет ли новый элемент вставляться в дубликат. Другими словами, такая карта будет иметь только элементы, которые не являются подстроками друг друга.

Поиск O (n) практически означает, что вы используете std::find() по карте с пользовательским предикатом, который принимает std::pair<std::string,std::string> и возвращает true, если второй элемент пары является подстрокой первого.

Ответ 4

typedef TStrStrMap::value_type map_value_type;

struct key_contains_substring
   : std::binary_function<map_value_type, std::string, bool>
{
    bool operator()(const map_value_type& map_value, const std::string& substr)
    {
         return std::search(map_value.first.begin(), map_value.first.end(),
                    substr.begin(), substr.end() != map_value.first.end());  
    }
};

...


TStrStrMap::const_iterator it = std::find_if(tMap.begin(), tMap.end(), 
        std::bind2nd(key_contains_substring(), "Marl");