如何从 std::set 绘制 n 个元素的样本

How to draw a sample of n elements from std::set

本文关键字:元素 样本 set std 绘制      更新时间:2023-10-16

我有以下函数从std::set中选择一个随机元素:

int pick_random(const std::set<int>& vertex_set) {
std::uniform_int_distribution<std::set<int>::size_type> dist(0, vertex_set.size() - 1);
const std::set<int>::size_type rand_idx = dist(mt);
std::set<int>::const_iterator it = vertex_set.begin();
for (std::set<int>::size_type i = 0; i < rand_idx; i++) {
it++;
}
return *it;
}

但是,我想知道如何从集合中正确绘制n元素的样本。使用 C++17 编译器,我可以使用std::sample函数,但这里的情况并非如此,因为我有 C++11 编译器。

如果您不介意复制,一个简单的方法是从std::set创建一个std::vector,使用std::shuffle对其进行洗牌,然后获取前n元素:

std::vector<int> pick_random_n(const std::set<int>& vertex_set, std::size_t n) {
std::vector<int> vec(std::begin(vertex_set), std::end(vertex_set));
std::shuffle(std::begin(vec), std::end(vec), mt);
vec.resize(std::min(n, vertex_set.size()));
return vec;
}

如果你不想要额外的副本,你可以看看std::sample的实现,例如libc++,并实现你自己的std::set

std::vector<int> pick_random_n(const std::set<int>& vertex_set, std::size_t n) {
auto unsampled_sz = vertex_set.size();
auto first = std::begin(vertex_set);
std::vector<int> vec;
vec.reserve(std::min(n, unsampled_sz));
for (n = std::min(n, unsampled_sz); n != 0; ++first) {
auto r =
std::uniform_int_distribution<std::size_t>(0, --unsampled_sz)(mt);
if (r < n) {
vec.push_back(*first);
--n;
}
}
return vec;
}