c++で、予め用意した配列からランダムで任意の個数抽出するという処理を行いたいのですが、どうすればよいでしょうか?例えば、100個の要素がある配列から10個の要素をランダムに抽出する、という感じです。
個人で考えた方法として、vector形式に保存して毎回shuffle関数で要素の並びをシャッフルし、先頭n個を抽出する、という方法を考えているのですが、shuffle関数が再現性のある処理なのかわからず、適しているかわからないのが現状です。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答4件
0
こんなんでどーぢゃろ
C++
1#include <random> 2#include <iterator> 3#include <algorithm> 4 5/* 6 [first, last) の中からでたらめにひとつ選び、 7 末尾要素と入れ替える 8*/ 9template<typename Iterator, typename Engine> 10void pop_random(Iterator first, Iterator last, Engine& eng) { 11 std::uniform_int_distribution<int> dist(0, std::distance(first,last)-1); 12 std::iter_swap(std::next(first, dist(eng)), std::prev(last)); 13} 14 15#include <iostream> 16#include <vector> 17#include <numeric> 18 19int main() { 20 std::vector<int> data(100); 21 std::iota(data.begin(), data.end(), 0); 22 23 std::mt19937 eng; 24 for ( int i = 0; i < 10; ++i ) { 25 pop_random(data.begin(), data.end(), eng); 26 std::cout << data.back() << std::endl; 27 data.pop_back(); // 選んだ要素を取り除く 28 } 29}
投稿2020/12/02 12:55
総合スコア16612
0
ベストアンサー
昔ドンピシャな内容について論じたことがあります。unordered_set
を使ってる例は除外するとして、再現性はいずれもseedにのみ依存します。
投稿2020/12/02 07:50
編集2020/12/02 07:52総合スコア5852
0
非復元抽出は C++17 以前であれば、「シャッフル → 先頭 n 個を取り出す」とすればいいのではないでしょうか。
shuffle - cpprefjp C++日本語リファレンス
C++17 では std::sample() を使えば非復元抽出が行えます。
cpp
1#include <algorithm> 2#include <iostream> 3#include <numeric> 4#include <random> 5#include <vector> 6 7static std::mt19937 engine(0); // シードを0で固定 8 9std::vector<int> sample(const std::vector<int> &v, size_t n) 10{ 11 if (v.size() < n) 12 n = v.size(); 13 14 // シャッフルする。 15 std::vector<int> v2(v); 16 std::shuffle(v2.begin(), v2.end(), engine); 17 18 // 先頭 n 個を取り出す。 19 std::vector<int> out(v2.begin(), v2.begin() + n); 20 21 return out; 22} 23 24int main() 25{ 26 std::vector<int> v(100); 27 std::iota(v.begin(), v.end(), 0); 28 29 // C++17未満 30 { 31 std::vector<int> out = sample(v, 10); 32 33 std::for_each(out.begin(), out.end(), [](int x) { std::cout << x << " "; }); 34 std::cout << std::endl; 35 } 36 37 // C++17 38 { 39 std::vector<int> out; 40 std::sample(v.begin(), v.end(), std::back_inserter(out), 10, engine); 41 42 std::for_each(out.begin(), out.end(), [](int x) { std::cout << x << " "; }); 43 std::cout << std::endl; 44 } 45} 46
shuffle関数が再現性のある処理なのかわからず
シャッフルも乱数生成器を利用しているので、乱数生成器のシードを固定すれば再現性は確保できます。
投稿2020/12/02 06:29
総合スコア21956
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/12/02 13:40 編集
2020/12/02 13:50
2020/12/04 12:45 編集
2020/12/04 13:47
2020/12/04 16:30
2020/12/06 08:05