It seems that, using shuffle(Index, Index+n, g)
before getting the first b
entries is still not efficient when n
is very big but b
is very small, where Index is a vector/array storing 0 ... (n-1)
.
Asked
Active
Viewed 126 times
2
-
3If you're grabbing fewer than `n` entries, why not sample indices instead of shuffling the entire collection? – AndyG Dec 29 '16 at 15:01
-
@AndyG Yes, but then how to do? – olivia Dec 29 '16 at 15:02
-
2@olivia: with [`sample`](http://en.cppreference.com/w/cpp/experimental/sample) perhaps? – Kerrek SB Dec 29 '16 at 15:02
-
Similar question [here](http://stackoverflow.com/q/3052788/1460794). – wally Dec 29 '16 at 15:03
2 Answers
1
You can take the standard shuffle algorithm and modify it to stop after shuffling just the first b
entries.

sh1
- 4,324
- 17
- 30
0
Here is a different idea than what sh1 suggests. Unlike a previous answer it is mathematically sound. No % BS.
#include <algorithm>
#include <iostream>
#include <iterator>
#include <ostream>
#include <random>
#include <set>
#include <vector>
int main()
{
// Configuration.
auto constexpr n = 100;
auto constexpr b = 10;
// Building blocks for randomness.
auto const seed = std::mt19937::result_type{ std::random_device{}() };
std::cout << "seed = " << seed << std::endl;
auto engine = std::mt19937{ seed };
auto distribution = std::uniform_int_distribution<>{};
// Creating the data source. Not part of the solution.
auto reservoir = std::vector<int>{};
std::generate_n(std::back_inserter(reservoir), n,
[i = 0]() mutable { return i++; });
// Creating the sample.
// Idea attributed to Bob Floyd by Jon Bentley in Programming Pearls 2nd Edition.
auto sample = std::set<int>{};
for (auto i = n - b; i != n; ++i)
{
auto const param = std::uniform_int_distribution<>::param_type(0, i);
auto const j = distribution(engine, param);
(sample.find(j) == sample.cend())
? sample.insert(j)
: sample.insert(i);
}
// Converting the sample to an output vector and shuffle it, if necessary.
auto output = std::vector<int>(std::cbegin(sample), std::cend(sample));
std::shuffle(std::begin(output), std::end(output), engine);
// Print out the result.
for (auto const x : output) { std::cout << x << " "; }
std::cout << std::endl;
return 0;
}

user515430
- 298
- 1
- 3
- 7