0

Is it possible to select efficiently a somewhat random element in abseil::node_hash_map, or more generally any abseil map?

For example, I'd be happy with an approach that selected a slot at random, then found the next occupied slot and chose a random element from within the elements hashed to that slot, but it isn't clear this is possible without access to the map internals.

Something like std::next(map, n) where n is an integer selected randomly between [0, map.size()) would work but is very slow with complexity O(map.size()).

BeeOnRope
  • 60,350
  • 16
  • 207
  • 386
  • If you are selecting a lot of random elements it may be worth caching the keys in a vector and selecting a random key from the vector each time? – Galik Dec 22 '20 at 05:46
  • @Galik - it's hard to keep the vector in sync with the map efficiently, e.g, deleting elements leaves a hole in the vector: erasing it is O(n), etc. – BeeOnRope Dec 22 '20 at 07:25
  • This won't be clean at all (or safe from code updates) but the [internals of abseil::node_hash_map](https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal/raw_hash_set.h) would allow you to select [a group](https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal/raw_hash_set.h) and find the first [valid byte](https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal/raw_hash_set.h#L260). They allocate the control bytes in a contiguous array so it has O(1) access (and relatively efficient search with ```SSE2``` and ```AVX```). – Noah Jan 11 '21 at 17:32

1 Answers1

0

No, you can't do that.

The closest you can get, is to create a separate array of pointers to node_hash_map elements, and then select randomly among those pointers. That way, the very first time you choose an element, it's O(N) time, but after that it's O(1).

jorgbrown
  • 1,993
  • 16
  • 23
  • 1
    Thanks. Only O(1) until the next mutation of the map, I suppose (unless you try to keep this array in sync with the map as mutations occur). – BeeOnRope Feb 06 '21 at 21:02