[英]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.