Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to std::hash an unordered std::pair

I want to be able to use a std::pair as a key in an unordered_container. I know that I could do this the following way:

template<typename T>
void
hash_combine(std::size_t &seed, T const &key) {
  std::hash<T> hasher;
  seed ^= hasher(key) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}

namespace std {
  template<typename T1, typename T2>
  struct hash<std::pair<T1, T2>> {
    std::size_t operator()(std::pair<T1, T2> const &p) const {
      std::size_t seed(0);
      ::hash_combine(seed, p.first);
      ::hash_combine(seed, p.second);
      return seed;
    }
  };
}

However, I want the hashing to ignore the order of the elements in the std::pair (i.e., to return the same seed for std::pair<A, B> and std::pair<B, A>).

One way I thought to achieve this is to apply some kind of ordering when creating my std::pair<A, B> (i.e., some kind of custom std::make_pair). But this is too restrictive since objects A, B might not have an order.

Q:

Is there a standard way to hash a std::pair, such that the order of elements is ignored and the same seed is returned either for std::pair<A, B> and std::pair<B, A>?

like image 457
101010 Avatar asked Feb 06 '15 14:02

101010


People also ask

Does std :: pair have hash?

However, std::pair is not hashable by default, so a simple snippet like the above would not work. There are many proposals online to define a pairhash class and explicitly specify it as the hash function as a template parameter to std::unordered_set and std::unordered_map . This is not a bad idea.

Can you hash a pair C++?

Unordered Map does not contain a hash function for a pair like it has for int, string, etc, So if we want to hash a pair then we have to explicitly provide it with a hash function that can hash a pair.

Can you have an unordered set of pairs?

An unordered set of pairs is an unordered set in which each element is a pair itself. By default, C++ doesn't allow us to create an unordered set of pairs directly but one can pass a hash function to the unordered set container.


1 Answers

Don't order the pairs, order the hashes:

namespace std {
  template<typename T1, typename T2>
  struct hash<std::pair<T1, T2>> {
    std::size_t operator()(std::pair<T1, T2> const &p) const {
      std::size_t seed1(0);
      ::hash_combine(seed1, p.first);
      ::hash_combine(seed1, p.second);

      std::size_t seed2(0);
      ::hash_combine(seed2, p.second);
      ::hash_combine(seed2, p.first);

      return std::min(seed1, seed2);
    }
  };
}

[Live example]

like image 92
Angew is no longer proud of SO Avatar answered Sep 17 '22 18:09

Angew is no longer proud of SO