Since C++ 11, we can use unordered sets and unordered maps. However, these data structures only seem to work with primitive types and strings. If you need a pair or a vector as the key, you’re out of luck. Fortunately, it’s possible to use unordered containers with other types, we just have to do some additional work, namely, define a hash function for the data type you need. Here are a couple of examples:
#include <bits/stdc++.h>
using namespace std;
struct VectorHash {
template <class T>
size_t operator()(const vector<T>& v) const {
// Simple hash function, though not necessarily a good one
int h = 0;
for (auto e : v) {
h ^= hash<T>{}(e);
}
return h;
}
};
struct PairHash {
template <typename T, typename U>
auto operator()(const pair<T, U> &p) const -> size_t {
// Simple hash function, though not necessarily a good one: if p.first and p.second are the
// same, the final has will be equal to zero.
return hash<T>{}(p.first) ^ hash<U>{}(p.second);
}
};
int main() {
unordered_map<pair<int, int>, int, PairHash> mapOfPairs;
mapOfPairs[{1, 2}]++;
mapOfPairs[{1, 2}]++;
mapOfPairs[{2, 1}]++;
mapOfPairs[{2, 1}]++;
for (auto& entry : mapOfPairs) {
cout << "{" << entry.first.first << ", " << entry.first.second << "}: " << entry.second << "\n";
}
cout << "\n";
unordered_map<vector<int>, int, VectorHash> mapOfVectors;
mapOfVectors[{1, 2, 3}] = 3;
mapOfVectors[{1, 2, 3, 4}] = 4;
mapOfVectors[{1, 2, 3, 4, 5}] = 5;
for (auto& entry : mapOfVectors) {
for (auto e : entry.first) {
cout << e << " ";
}
cout << ": ";
cout << entry.second << "\n";
}
return 0;
}
There you have it, an easy way to make unordered containers work with custom types.
References
- C++ unordered_map using a custom class type as the key on StackOverflow
- How to create an unordered_map of pairs in C++? on GeeksForGeeks