How can I pick multiple values randomly in any given integer range?
With std::sample()
,
one possible implementation would be:
void Sample(
int first, int last, std::vector<int> *out, std::size_t n, std::mt19937 *g)
{
std::vector<int> in{};
for (int i = first; i < last; i)
{
in.emplace_back(i);
}
std::sample(in.begin(), in.end(), std::back_inserter(*out), n, *g);
}
But I'm hesitating because creating in
vector seems redundant and impractical,
especially when first
is 0 and last
is very big number.
Is there any public implementation or library for this requirement? e.g.:
sample(int first, int last, ...)
or,ranges::sample(int n, ...)
CodePudding user response:
In C 20 you can sample on iota_view
#include <ranges>
#include <vector>
#include <algorithm>
#include <random>
void Sample(
int first, int last, std::vector<int> *out, std::size_t n, std::mt19937 *g)
{
std::ranges::sample(
std::views::iota(first, last), std::back_inserter(*out), n, *g);
}
Note that the above does not work in libstdc because ranges::sample
incorrectly uses the std::sample
's implementation. Since iota_view
's iterator only satisfies Cpp17InputIterator
, std::sample
requires that the output range must be a random access iterator, which is not the case for back_inserter_iterator
.
The workaround is to pre-resize the vector
.
void Sample(
int first, int last, std::vector<int> *out, std::size_t n, std::mt19937 *g)
{
out->resize(n);
std::ranges::sample(
std::views::iota(first, last), out->begin(), n, *g);
}
which works in both libstdc and MSVC-STL.