How to use unordered_set that has elements that are vector of pair<int,int>

半腔热情 提交于 2019-11-28 18:52:32

You could implement it like this, based on boost::hash_combine for a sensible calculation of hashes:

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <unordered_set>

namespace
{
    // a little helper that should IMHO be standardized
    template<typename T>
    std::size_t make_hash(const T& v)
    {
        return std::hash<T>()(v);
    }

    // adapted from boost::hash_combine
    void hash_combine(std::size_t& h, const std::size_t& v)
    {
        h ^= v + 0x9e3779b9 + (h << 6) + (h >> 2);
    }

    // hash any container
    template<typename T>
    struct hash_container
    {
        size_t operator()(const T& v) const
        {
            size_t h=0;
            for( const auto& e : v ) {
                hash_combine(h, make_hash(e));
            }
            return h;
        }
    };
}

namespace std
{
    // support for pair<T,U> if T and U can be hashed
    template<typename T, typename U>
    struct hash<pair<T, U>>
    {
        size_t operator()(const pair<T,U>& v) const
        {
            size_t h=make_hash(v.first);
            hash_combine(h, make_hash(v.second));
            return h;
        }
    };

    // support for vector<T> if T is hashable
    // (the T... is a required trick if the vector has a non-standard allocator)
    template<typename... T>
    struct hash<vector<T...>> : hash_container<vector<T...>> {};

    // the same for map<T,U> if T and U are hashable
    template<typename... T>
    struct hash<map<T...>> : hash_container<map<T...>> {};

    // simply add more containers as needed
}

int main()
{
    std::unordered_set<std::vector<std::pair<int,int>>> us;
    us.insert(std::vector<std::pair<int,int>>{{{42,0},{17,64}}});
    std::cout << us.size() << std::endl;
    std::cout << us.begin()->size() << std::endl;
    std::cout << us.begin()->begin()->first << std::endl;

    std::unordered_set<std::map<int,int>> usm;
    std::map<int,int> m{{42,0},{17,64}};
    usm.insert(m);
}

Live example

Note that there was a problem when combining Clang with libstdc++ which might affect you when specializing std::hash. It has been fixed with GCC 4.8.2, but it is still visible on Coliru. If this is a problem in your case, you could disable the warning with -Wno-mismatched-tags and Clang will no longer complain.

You should write a hasher for your types, for example:

class MyHash
{
public:
    std::size_t operator()(const vector<pair<int,int>> &v) const
    {
        std::size_t x = 0;

        for (auto &i : v)
            x ^= std::hash<int>()(i.first) ^ std::hash<int>()(i.second);

        return x;
    }
};


int main()
{
    unordered_set<vector<pair<int,int>>, MyHash> um;
}

Note: The hash function that I wrote is just an example, it can be replaced with another and better one.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!