How to use unordered_set that has elements that are vector of pair

前端 未结 2 1284
别那么骄傲
别那么骄傲 2020-12-13 21:05

I wanted to have something like

 unordered_set>> us;

but even without pair:

#includ         


        
相关标签:
2条回答
  • 2020-12-13 21:38

    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.

    0 讨论(0)
  • 2020-12-13 21:45

    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.

    0 讨论(0)
提交回复
热议问题