3

std::map在我的项目中使用 a ,因为我想将几个不同的字符串相互映射。例如,我可能会创建一个类似于此的地图:

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'

我希望你明白我在追求什么。我想有效地检索映射到与比它们大的比较键相对应的键的值,但共享相同的前缀(例如“测试”)。

我不知道std::map在这种情况下是否是最佳选择,如果不是,请告知其他选择。

注意:我尝试使用带有std::greater_equal作为键比较器的映射与该lower_bound方法相结合,但最终出现运行时错误,并且我也质疑这种方法的效率。

4

4 回答 4

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";
}
于 2013-10-01T16:20:04.790 回答
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 这样的解析器生成器。

于 2013-10-01T18:00:26.107 回答
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";
    }
于 2013-10-01T18:30:22.943 回答
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

注意:这段代码展示了一堆不同的方法来做同样的事情。只使用你需要的东西。我个人认为最后一个是最简单和最容易阅读的,因为它不会分散代码远离它的使用。

于 2013-10-01T20:24:09.313 回答