6

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!!!

3
  • "I wonder what is h = h * 31 + hasher(a[i]);" - In this line you just calculate a hash for your array. What exactly do not you understand? Commented Jun 14, 2013 at 15:48
  • @soon what is 31? I asked about this and some nice guy gave me this template... Commented Jun 14, 2013 at 15:56
  • 31 is just a constant. It depends on your restrictions for elements in an array. Commented Jun 14, 2013 at 16:09

2 Answers 2

1

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;
Sign up to request clarification or add additional context in comments.

Comments

1

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.

1 Comment

You usually do not use any cryptographic hash unless you really need it. Cryptographic hashes are computationally more intensive. Additionally, finding a perfect hash function (w/o collisions for your application) is always a challenge. In most cases, the standard implementation works very well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.