1

My code works just fine when I use map< array<int,FIXEDSIZE>, int> but not when I use unordered_map< array<int,FIXEDSIZE>, int>.

It creates this massive list of errors so I don't really know what's wrong. Things like "value" is not a member, or "no match for operator[]", etc.

This is how I am using my map (which I name cache):

if (cache.find(key) != cache.end()) return cache[key];

and

cache[key] = valueToMemoize;
13
  • Why would you want something like this? Commented Nov 27, 2015 at 22:08
  • @101010 Memoization speed. In my experience, whenever unordered_map works, it's always a heck of a lot faster than using a regular map. I am trying to get unordered_map to work so I can compare. Commented Nov 27, 2015 at 22:09
  • You need to write a hasher. std::array comes with comparison operators (making it usable in maps), but no hashers. Commented Nov 27, 2015 at 22:11
  • 1
    As a side note, if (cache.find(key) != cache.end()) return cache[key]; searches for key twice. You should use at for that, or access the value by the iterator. Commented Nov 27, 2015 at 22:16
  • 1
    @user5613205 [] searches for it again, but at() doesn't help either. Commented Nov 27, 2015 at 22:19

2 Answers 2

2

This is basically what boost::hash_combine boils down to:

void hash_combine(std::size_t& seed, std::size_t value) {
    seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2);
}

A simple hasher for containers - hash all of their elements using std::hash, and combine them.

struct container_hasher {
     template<class T>
     std::size_t operator()(const T& c) const {
         std::size_t seed = 0;
         for(const auto& elem : c) {
             hash_combine(seed, std::hash<typename T::value_type>()(elem));
         }
         return seed;
     }
};

Use:

std::unordered_map<std::array<int, 10>, int, container_hasher> my_map;

For cheaper lookup, do

auto r = cache.find(key);
if(r != cache.end()) return r->second;

For std::map, you might want to use lower_bound instead, to help with the later insertion:

auto lb = cache.lower_bound(key);
if(lb != cache.end() && lb->first == key) return lb->second;
cache.emplace_hint(lb, key, valueToMemoize);
Sign up to request clarification or add additional context in comments.

3 Comments

I had found something similar at stackoverflow.com/questions/7222143/… so I am at least happy to know I was on the right track. Thank you for this! I'll have to study this a little to better understand how it works.
Also what is value + 0x9e3779b9 + (seed<<6) + (seed>>2);?
@user5613205: Note that combining hashes produces low-quality hashing which may perform poorly on certain inputs (and is attackable). While hash combining can be used to make the code "work", there's no substitute for hashing all the ingredient bits of the data in one go -- which is not easy to do with the current library design.
0

You need to define your custom hash object like below:

template<typename T, std::size_t N>
class arrayHash {
public:
  std::size_t operator()(std::array<T, N> const &arr) const {
    std::size_t sum(0);
    for(auto &&i : arr) sum += std::hash<T>()(i);
    return sum;
  }
};

And then define your unordered_map as:

std::unordered_map<std::array<int, FIXEDSIZE>, int, arrayHash<int, FIXEDSIZE>> umap;

Live Demo

Comments

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.