weeo
weeo

Reputation: 2839

C++ How to insert array to unordered_map as its key?

Hi I used to have a unordered_set to hold my 16 int array, now I need to store one more int as its bucket. I wonder if I can insert the array into my unordered_set, or can I use the same template I used to use?

#include <unordered_set>
#include <array>

namespace std
{
    template<typename T, size_t N>
    struct hash<array<T, N> >
    {
        typedef array<T, N> argument_type;
        typedef size_t result_type;

        result_type operator()(const argument_type& a) const
        {
            hash<T> hasher;
            result_type h = 0;
            for (result_type i = 0; i < N; ++i)
            {
                h = h * 31 + hasher(a[i]);
            }
            return h;
        }
    };
}

std::unordered_set<std::array<int, 16> > closelist;

int main()
{
    std::array<int, 16> sn = {1,2,3,4,5,6,0,8,9,10,11,12,13,14,7,15};
    closelist.insert(sn);
}

Can I just change it to this?

std::unordered_map<std::array<int, 16>,int > closelist;

    int main()
    {
        std::array<int, 16> sn = {1,2,3,4,5,6,0,8,9,10,11,12,13,14,7,15};
        closelist.insert(sn,24);
    }

And I couldn't understand the template, I wonder what is "h = h * 31 + hasher(a[i]);"?

Thank you!!!

Upvotes: 6

Views: 5219

Answers (2)

Andrey Tuganov
Andrey Tuganov

Reputation: 361

How to use any object as a key:

  1. Serialize the object into a byte array (for an array of ints just use the binary data as it is)
  2. Compute the cryptographic hash (MD5 or SHA)
  3. Convert the cryptographic hash into a fingerprint value (for example cast its first 64 bits into uint64_t)
  4. Use this fingerprint as a map key

The disadvantage is that you might need to resolve collisions somehow.

Upvotes: 1

awesoon
awesoon

Reputation: 33701

Can I just change it to this?

Firstly, your array initialization is wrong:

std::array<int, 16> sn = {{1,2,3,4,5,6,0,8,9,10,11,12,13,14,7,15}};
//                        ^                                     ^

Since std::array has no constructor with std::initializer_list as argument. So, first level for initializing an object, second for initializing an array in the object.

Secondly, from reference:

std::pair<iterator,bool> insert( const value_type& value );

template <class P> 
std::pair<iterator,bool> insert( P&& value );

So, you should pass std::pair(or something, convertible to std::pair), for example:

closelist.insert({sn,24});

Or, simpler:

closelist[sn] = 24;

Upvotes: 1

Related Questions