Reputation: 187
Given a set of integers:
std::set<int> itemInTest;
There are about 4000 integers in this set and I want to loop 100 times, each time it can pick 100 different elements from the set randomly. In addition, all the integers are positive.
how to randomly pick one of them each time? I know there are many answers in stackoverflow, but some are too complex and some are not so random.
Upvotes: 4
Views: 826
Reputation: 249103
First, put your items into a vector since you will need to randomly access them many times:
vector<int> items(itemInTest.begin(), itemInTest.end());
Then, if you need 100 items and don't want to pick the same one twice, you may as well just shuffle the whole thing:
std::random_device rd;
std::mt19937 gr(rd());
shuffle(items.begin(), items.end(), gr);
Now just take the first 100 elements. If you want them in a set again:
set<int> result(items.begin(), items.begin() + 100);
Or you can use any output container type you like--including vector.
You can do the random_shuffle
step again until you finish your 100 overall iterations.
If you don't have C++11, you can use std::random_shuffle()
instead of std::shuffle()
, noting that the quality of randomness may be reduced. Then you don't need std::mt19937
, just:
random_shuffle(items.begin(), items.end());
Upvotes: 8
Reputation: 217085
You may use Fisher–Yates shuffle:
Something like:
// Fisher–Yates_shuffle
std::vector<int> FisherYatesShuffle(std::size_t size, std::size_t max_size, std::mt19937& gen)
{
assert(size < max_size);
std::vector<int> b(size);
for(std::size_t i = 0; i != max_size; ++i) {
std::uniform_int_distribution<> dis(0, i);
std::size_t j = dis(gen);
if(j < b.size()) {
if(i < j) {
b[i] = b[j];
}
b[j] = i;
}
}
return b;
}
then from indexes, you take value from your set (which should be transformed into vector
for random access).
Upvotes: 1