我在项目中使用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
方法的地图,但我最终遇到了运行时错误,我也质疑这种方法的效率。
答案 0 :(得分:5)
以下将满足您的需求:
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";
}
答案 1 :(得分:2)
这段代码非常有效:
#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这样的解析器生成器。
答案 2 :(得分:0)
如果你不介意改变地图中元素的顺序,这应该有效并且非常简单:
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";
}
答案 3 :(得分:0)
使用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
注意:此代码显示了一堆不同的方法来执行相同的操作。只使用你需要的东西。我个人认为最后一个是最简单易读的,因为它不会远离它的使用而散布代码。