簡體   English   中英

在std :: map中部分匹配長鍵

[英]Partially match long key in std::map

我在我的項目中使用了std::map ,因為我想要將幾個不同的字符串相互映射。 例如,我可能會創建一個類似於此的地圖:

std::map<std::string, std::string> map;

map["test"] = "Foo";
map["blah"] = "Drei";
map["fayh"] = "Najh";
// And so on...

我想使用比地圖中的鍵更長的鍵找到這些值,即部分匹配鍵。 地圖中的所有鍵與它們所比較的鍵共享相同的前綴

這就是我想要實現的目標:

// Same map as earlier
std::cout << map.find('test123').second;    // Should output 'Foo'
std::cout << map.find('test_2165').second;  // Should output 'Foo' as well
std::cout << map.find('tes').second;        // Key not found
std::cout << map.find('fayh_TK_Ka').second; // 'Najh'

我希望你明白我的意思。 我想有效地檢索映射到鍵的值,這些鍵對應於比它們大的比較鍵,但共享相同的前綴(例如'test')。

我不知道std::map是否是這種情況下的最佳選擇,如果沒有,請告訴其他選項。

注意:我已經嘗試使用帶有std::greater_equal的映射作為關鍵比較器和lower_bound方法,但我最終遇到了運行時錯誤,我也質疑這種方法的效率。

以下將滿足您的需求:

std::string my_find( const std::string& s )
{
    auto it = map.lower_bound( s );
    if( it != map.begin() ) {
        if( it != map.end() && it->first == s ) return it->second; // exact match
        --it;
        if( it->first == s.substr( 0, it->first.size() ) ) {
            return it->second;
        }
    }
    return "Key not found";
}

這段代碼非常有效:

#include <algorithm>
#include <vector>
#include <iostream>

typedef std::pair<std::string, std::string> Strings;
typedef std::vector<Strings> Values;

std::string findValue( const Values &vals, const std::string &str )
{
   auto it = std::lower_bound( vals.begin(), vals.end(), Strings( str, std::string() ), []( const Strings &s1, const Strings &s2 ) {
      size_t len = std::min( s1.first.length(), s2.first.length() );
      return s1.first.substr( 0, len ) < s2.first.substr( 0, len );
   } );
   if( it == vals.end() || it->first.length() > str.length() ) return std::string();
   return it->second;
}

void test(  const Values &vals, const std::string &str )
{
   std::cout << "testing \"" << str << "\" - \"" << findValue( vals, str ) << "\"" << std::endl;
}

int main()
{
    Values vals { { "test", "Foo" }, { "blah", "Drei" }, { "fayh", "Najh" } };
    std::sort( vals.begin(), vals.end(), []( const Strings &s1, const Strings &s2 ) { return s1.first < s2.first; } );

    test( vals, "test123" );
    test( vals, "test_2165" );
    test( vals, "test" );
    test( vals, "tes" );

    return 0;
}

如果您的數據當然是靜態的,那么對於更高效的解決方案,您可以使用像lex這樣的解析器生成器。

如果你不介意改變地圖中元素的順序,這應該是有效的,並且非常簡單:

    std::map<std::string, std::string, std::greater<std::string>> map;
    map["test"] = "Foo";
    map["blah"] = "Drei";
    map["fayh"] = "Najh";

    std::string s = "fay";

    auto i = map.lower_bound(s);
    if (i != map.end() && std::equal(i->first.begin(), i->first.end(), s.begin())) {
        std::cout << i->first << " -> " << i->second << "\n";
    } else {
        std::cout << "not found\n";
    }

使用std::map的能力從std::map外部定義比較器,如下所示:

#include <iostream>
#include <map>
#include <string>
#include <string.h>
#include <functional>

using namespace std;

// Define comparator functor:
struct functor_test
{
    bool operator()(string const & lhs, string const & rhs)
    {
        return strncmp(lhs.c_str(), rhs.c_str(), 4) < 0;
    }
};

// Define comparator function:
bool function_test(string const & lhs, string const & rhs)
{
    return strncmp(lhs.c_str(), rhs.c_str(), 4) < 0;
}

int main() {
    // Define comparator lambda:
    auto lambda_test = [](string const & lhs, string const & rhs)
    {
        return strncmp(lhs.c_str(), rhs.c_str(), 4) < 0;
    };

    // These are all valid ways to declare the key comparitor:

    //As a functor:
    //  map<string, string, functor_test>                                 map;

    //As a function using a function reference type:
    //  map<string, string, bool(&)(string const&, string const&)>        map(function_test);

    //As a function using a function pointer type:
    //  map<string, string, bool(*)(string const&, string const&)>        map(function_test);

    //As a function using a function class type wrapper:
    //  map<string, string, function<bool(string const&, string const&)>> map(function_test);

    //As a predefined lambda:
    //  map<string, string, decltype(lambda_test)>                        map(lambda_test);

    //As a predefined lambda using a function class type wrapper:
    //  map<string, string, function<bool(string const&, string const&)>> map(lambda_test);

    //As a lambda using a function class type wrapper:
    map<string, string, function<bool(string const&, string const&)>>   map(
        [](string const & lhs, string const & rhs)
        {
            return strncmp(lhs.c_str(), rhs.c_str(), 4) < 0;
        });

    map["test"] = "Foo";
    map["blah"] = "Drei";
    map["fayh"] = "Najh";

    std::cout << map.find("test123")->second << endl;    // Should output 'Foo'
    std::cout << map.find("test_2165")->second << endl;  // Should output 'Foo' as well
    if (map.find("tes") == map.end())
    {
        cout << "Not found" << endl;
    }// Key not found
    std::cout << map.find("fayh_TK_Ka")->second << endl; // 'Najh'

    return 0;
}

要使用工作演示,請訪問: http//ideone.com/sg4sET

注意:此代碼顯示了一堆不同的方法來執行相同的操作。 只使用你需要的東西。 我個人認為最后一個是最簡單易讀的,因為它不會遠離它的使用而散布代碼。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM