如何从具有std::unordered_multimap
等效键的元素组中选择随机元素?
这样做的惯用方法是什么?我知道我可以使用mmap.equal_range(key)
获取给定键的元素范围。有没有办法使用这个范围作为均匀分布的界限?
答案 0 :(得分:2)
std::unordered_multimap::count
:返回键键的元素数。
std::unordered_multimap::equal_range
:返回包含容器中带有键键的所有元素的范围。范围由两个迭代器定义,第一个指向所需范围的第一个元素,第二个指向范围的最后一个元素。
所以,很容易(我猜):
auto n = random(0, my_map.count(key) - 1);
auto val = std::next(my_map.equal_range(key).first, n)->second;
我在这里做的只是使用std::next
推进迭代器。 random
是您可能想要使用的更复杂的统一int分布的简写。
答案 1 :(得分:1)
您可以使用bucket
成员函数来获取存储某个密钥的存储桶,然后只检查具有本地迭代器的那个存储桶:
T const & get_random(std::unordered_map<K, T> const & m)
{
auto const b = m.bucket(k);
// return random element from [m.begin(b), m.end(b))
}
答案 2 :(得分:1)
看看以下代码:
#include <iostream>
#include <unordered_map>
#include <string>
#include <random>
static std::mt19937_64 rng;
int main()
{
std::unordered_multimap<std::string, std::string> fruits = {
{ "apple", "red" },
{ "apple", "green" },
{ "apple", "blue"},
{ "apple", "white"},
{ "apple" , "black"},
{ "orange", "orange" },
{ "strawberry", "red" }
};
std::random_device rd; // obtain a random number from hardware
std::mt19937 eng(rd()); // seed the generator
for (auto i(0); i < fruits.bucket_count(); ++i) {
auto d = std::distance(fruits.begin(i), fruits.end(i));
if (d > 0) {
std::uniform_int_distribution<> distr(0, d - 1); // define the range
auto r = distr(eng);
std::cout << "random index = " << r << std::endl;
auto elem = fruits.begin(i);
std::advance(elem, r);
std::cout << elem->first << " : " << elem->second << std::endl;
}
}
return 0;
}
更便携和通用的版本:
#include <iostream>
#include <unordered_map>
#include <string>
#include <random>
static std::mt19937_64 rng;
// Returns random iterator from an input range.
template<typename LIST_ITERATOR>
LIST_ITERATOR
getRandomIteratorFromRange(LIST_ITERATOR const &begin,
LIST_ITERATOR const &end,
std::mt19937 &random_engine)
{
auto d = std::distance(begin, end);
if(d > 0) {
LIST_ITERATOR out(begin);
std::advance(out, std::uniform_int_distribution<>(0, d - 1).operator()(random_engine));
return out;
}
return end;
}
int main()
{
std::unordered_multimap<std::string, std::string> fruits = {
{"apple", "red"}, { "apple", "green" }, { "apple", "blue" }, { "apple", "white" },
{"apple", "black"}, {"apple", "pink"},{"orange","orange"},{"strawberry", "red"}};
std::random_device rd; // obtain a random number from hardware
std::mt19937 eng(rd()); // seed the generator
for(auto i(0); i < fruits.bucket_count(); ++i) {
auto it = getRandomIteratorFromRange(fruits.begin(i), fruits.end(i), eng);
if(it != fruits.end(i)) std::cout << it->first << " : " << it->second << std::endl;
}
return 0;
}