unordered_map:带有一对std :: string_view的std :: string的查找对

发布于 2025-02-09 18:58:39 字数 392 浏览 2 评论 0 原文

给定一个在一对字符串上键入的hashmap,例如:

std :: unordered_map< std :: pair< string,string>,int> mymap;

如何使用一对std :: string_view(例如:

std::string s = "I'm a string";
std::string s2 = "I'm also a string";

std::string_view sv(s);
std::string_view sv2(s2);
myMap.find(std::make_pair(sv, sv2));

我想我需要在某个地方定义自己的比较器)进行查找,但是我不确定从哪里开始。

Given a hashmap that is keyed on a pair of strings, e.g:

std::unordered_map<std::pair<String, String>, int> myMap;

How could one do a lookup with a pair of std::string_view, e.g:

std::string s = "I'm a string";
std::string s2 = "I'm also a string";

std::string_view sv(s);
std::string_view sv2(s2);
myMap.find(std::make_pair(sv, sv2));

I guess that I need to define my own comparator somewhere, but I'm not sure where to begin.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

十秒萌定你 2025-02-16 18:58:39

使用C ++ 20年代的异质查找,可以完成此操作(请参阅 unordered_map :: find() )。为此,必须定义一个hash函数和平等函数,例如:

struct hash {
    template <typename T>
    auto operator()(const std::pair<T, T>& pair) const {
        return std::hash<T>{}(pair.first) ^ std::hash<T>{}(pair.second); // not to be used in production (combining hashes using XOR is bad practice)
    }

    using is_transparent = void; // required to make find() work with different type than key_type
};

struct equal {
    template <typename A, typename B>
    auto operator()(const std::pair<A, A>& a,
                    const std::pair<B, B>& b) const {
        return a.first == b.first && a.second == b.second;
    }

    using is_transparent = void; // required to make find() work with different type than key_type
};

地图的类型必须更改为 std :: unordered_map&lt&std :: pair&lt&lt&std :: string :: std :: std ::字符串&gt;,int,hash,quare&gt; ,以便使用定义的函数。

find()现在按预期工作:

using namespace std::literals;

std::unordered_map<std::pair<std::string, std::string>, int, hash, equal> map{};

map.insert({std::pair{"a"s, "b"s}, 42});

if (auto it = map.find(std::pair{"a"sv, "b"sv}); it != map.end())
  std::cout << it->second << std::endl;

if (auto it = map.find(std::pair{"x"s, "y"s}); it != map.end())
  std::cout << it->second << std::endl;

// prints 42

可以使用在这里

With C++20's heterogeneous lookups this can be done (see documentation of unordered_map::find()). For this to work a hash functor and a equality functor have to be defined, e.g.:

struct hash {
    template <typename T>
    auto operator()(const std::pair<T, T>& pair) const {
        return std::hash<T>{}(pair.first) ^ std::hash<T>{}(pair.second); // not to be used in production (combining hashes using XOR is bad practice)
    }

    using is_transparent = void; // required to make find() work with different type than key_type
};

struct equal {
    template <typename A, typename B>
    auto operator()(const std::pair<A, A>& a,
                    const std::pair<B, B>& b) const {
        return a.first == b.first && a.second == b.second;
    }

    using is_transparent = void; // required to make find() work with different type than key_type
};

The type of the map then has to be changed to std::unordered_map<std::pair<std::string, std::string>, int, hash, equal> in order to use the defined functors.

find() now works as intended:

using namespace std::literals;

std::unordered_map<std::pair<std::string, std::string>, int, hash, equal> map{};

map.insert({std::pair{"a"s, "b"s}, 42});

if (auto it = map.find(std::pair{"a"sv, "b"sv}); it != map.end())
  std::cout << it->second << std::endl;

if (auto it = map.find(std::pair{"x"s, "y"s}); it != map.end())
  std::cout << it->second << std::endl;

// prints 42

The implementation can be played with here

百变从容 2025-02-16 18:58:39

由于您正在使用 unordered_map ,因此您需要为您的自定义密钥类型提供 hash函数 keyequal ,而不是键类型的比较器仅通过排序的容器(例如 set/map )或排序的容器适配器( PRIRISITION_QUEUE )才需要。

在您的示例中,密钥类型为 pair&lt; string_view,string_view&gt; std :: Pair 类型已经定义了其 == 运算符,但它不提供哈希功能。因此,我们只需要为 std :: Pair 类型定义哈希函数。幸运的是,STL已经为 std :: String_view 提供了哈希模板专业化,这使我们的任务变得更加容易。这是代码:

#include <iostream>
#include <string>
#include <string_view>
#include <unordered_map>
 
struct Hash {
    size_t operator()(const std::pair<std::string_view, std::string_view> &key) const {
        return std::hash<std::string_view>()(key.first) ^ std::hash<std::string_view>()(key.second);
    }
};

int main() {
    std::unordered_map<std::pair<std::string_view, std::string_view>, int, Hash> myMap;

    std::string s = "I'm a string";
    std::string s2 = "I'm also a string";
    
    std::string_view sv(s);
    std::string_view sv2(s2);
    
    myMap.insert({{sv, sv2}, 1});
    
    // To print the map
    for (auto &[key, val] : myMap) {
        std::cout << "{" << key.first << ", " << key.second << "}: " << val << std::endl;
    }
    
    // To search
    auto it = myMap.find({sv, sv2});
    if (it != myMap.end()) std::cout << "Found key with value: " << it->second << std::endl;
    
    return 0;
}

输出是:

{I'm a string, I'm also a string}: 1
Found key with value: 1

Since you are using unordered_map, then you need to provide Hash function and KeyEqual for your custom key type, not the comparator for the key type which is needed only by sorted containers (such as set/map) or sorted container adapter (priority_queue).

In your example, the key type is pair<string_view, string_view>. The std::pair type already defines its == operator, but it provides no hash function. So we only need to define a hash function for the std::pair type. Fortunately, STL already provides the hash template specialization for std::string_view, which makes our task much easier. Here is the code:

#include <iostream>
#include <string>
#include <string_view>
#include <unordered_map>
 
struct Hash {
    size_t operator()(const std::pair<std::string_view, std::string_view> &key) const {
        return std::hash<std::string_view>()(key.first) ^ std::hash<std::string_view>()(key.second);
    }
};

int main() {
    std::unordered_map<std::pair<std::string_view, std::string_view>, int, Hash> myMap;

    std::string s = "I'm a string";
    std::string s2 = "I'm also a string";
    
    std::string_view sv(s);
    std::string_view sv2(s2);
    
    myMap.insert({{sv, sv2}, 1});
    
    // To print the map
    for (auto &[key, val] : myMap) {
        std::cout << "{" << key.first << ", " << key.second << "}: " << val << std::endl;
    }
    
    // To search
    auto it = myMap.find({sv, sv2});
    if (it != myMap.end()) std::cout << "Found key with value: " << it->second << std::endl;
    
    return 0;
}

output is:

{I'm a string, I'm also a string}: 1
Found key with value: 1
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文