🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

7回答

25284閲覧

重複しない乱数

Hoshi

総合スコア10

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

2グッド

2クリップ

投稿2015/03/23 20:47

繰り返しの中で乱数を発生させたいのですが、その乱数を重複しないようにするためにはどうすればよいのでしょうか?以下にコードを示します。

lang

1for (int i =0 ; i < 5 ; i++) 2 { 3 Random r = new Random(); 4 int lots = r.Next(10); //5回の繰り返しで乱数を重複させないようにしたい 5 }
oriduru👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答7

0

参考情報:

投稿2015/03/23 21:43

katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

配列作ってシャッフルするだけでしょ。

たとえば、1~10までの配列作ってシャッフル、絶対重複しない

C# にシャッフルや、sort があるかは知らないけど、シャッフルがあるならそれをかますだけだし、sort があるなら、判別関数に、ランダム関数を渡すだけ

投稿2015/03/24 07:51

miya

総合スコア81

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

>繰り返しの中で乱数を発生させたいのですが、
>その乱数を重複しないようにするためにはどうすればよいのでしょうか?
トランプのシャッフル、の方法で検索されると事例が見つかると思います。
(ゲームとしての、トランプのシャッフルでは、
意図して、片寄のあるシャッフルを行う事が普通です。
完全に混ぜてしまうと、ゲームになりません。)
簡単に、今回は、1~10迄の数値とします。
1.10個の配列を用意します。
2.1~10の値を、順に、各要素とします。
3.配列の要素を入れ替える為の、配列番号に相当する乱数を発生させます。
4.発生させた乱数で、配列同志の内容を入れ替えます。
5.入替終了後、配列を、昇順でも、降順でも良いので、
順番にアクセスすれば、重複しない値が取得できます。

コンピュータ系の、乱数と呼ばれている機能は、
正規乱数ではないので、片寄が発生します。
これを避けるようにする、乱数ジェネレータの為のコードが、
検索で見つかりますので、工夫してみてください。
⇒全うな、乱数発生機器は高いので、正規乱数でないのが解っていながら、
プログラムでは、正規乱数でない乱数を、工夫して使っています。

乱数の片寄を、視覚化する方法として、
8ビットパソコンの時代から行われている方法は、
100×100~ 位の範囲に
乱数値をプロットしていく方法があります。
ドット1回目は、最暗色、同じ処に、ドットを描画する度に
明るい色になるようにして、描画します。
(1600万色表示できる現在では、色変化は大きくしないと、
色変化が解らないかも。)

投稿2015/03/24 01:36

daive

総合スコア2030

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

どのような物が必要か にもよりますね。
例えばトランプや麻雀のような資源が限られてるような乱数であればその分を配列等に用意しシャッフルします。
C#カテゴリですので、C# シャッフル とかで検索すれば例はたくさん出てくると思いますよ。

RPGのようなものでユーザーに気遣って、2回連続で攻撃が外れることは絶対に無いのようなものであれば、攻撃が外れたらフラグを立てて、次の回では乱数処理をせずに確実に当たるのようにしたり(乱数ではないですね)
1/256がたまたま◯回中に同じのは出ないようにしたいのであれば、出た乱数を保持し比較してすでに出たのが含まれていたらもう一度乱数を回すのようにしたりも考えられます。(この手段は「最悪」無限ループします。◯回が少なくなったり母数が大きくなったりするとその可能性は下がります。)

必要とされるのは一般的にはシャッフルによる手法かと思われます。
母数があまりにも大きくなると処理速度やリソースの問題出てきてしまうかと思いますが。

投稿2016/03/01 06:53

Nikumo

総合スコア17

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Random 限定でやる場合だとシードにループ値を含めるだけでもずいぶん結果が異なります。
既に体験済みだと思いますがRandomは時間をデフォルトシードにしているのでごく短い間隔で乱数を生成すると値が重複しちゃいます。(こういう厳密な乱数とは異なるものを擬似乱数といういうそうですが)
コードは省略しますが、前回生成した乱数+実行回数 (intのオーバーフロー対策込み)をシード値にすると今のところ連続生成しても同じ値が連続で出現し続けるのを回避できています。

あとはループ回数が事前にわかっている(forで実現できる)場合は暗号化やハッシュに用いる為の、より「乱数」に近い擬似乱数を生成するアルゴリズムも利用できると思います。
→ System.Security.Cryptography.Rfc2898DeriveBytes
→ System.Security.Cryptography.RNGCryptoServiceProvider
Randomと使い方が異なるのでご参考までにどうぞ

投稿2015/03/24 01:07

Ryzna

総合スコア85

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Ryzna

2015/03/24 01:23

一応参考としてそれっぽいコード書いてみました。静的関数で書いてあるのは特に気にしなくて良いです。たぶんクラスにしたほうが良いはずですし。 private static int executeCount = 0; private static int prevResult = 0; private static int Random(int max) { Random r = null; if ( executeCount == 0) r = new Random(); else r = new Random( unchecked( executeCount + prevResult )); executeCount = unchecked( executeCount + 1); return r.Next(max); } 一応私自身が使ってるコードの簡略化版なのでまったくだめってことはないと思います。。。たぶん。。。きっと。。。
Ryzna

2015/03/24 01:24

メソッドがprivate宣言されているのも特に意味はないです・・・
Ryzna

2015/03/24 04:31

すみません。どうやら神経衰弱関連のご質問であることを知らずに早とちりしてしまいました。お騒がせしました。 (上のコードもprevResultに代入するところが抜けてるしもう少し落ち着きを持ちます;)
guest

0

これは一つの考えであって、最適解ではないとは思いますが、
int length = 5;
int[] array = new int[length];
for (int i = 0; i < length; i++ )
array[i] = i;

for( int i = 0; i < randomCount; i++ ){
int num1 = rand(0, length);
int num2 = rand(0, length);
int temp = array[num1];
array[num1] = array[num2];
array[num2] = temp;

}

for(int i = 0; i < length; i++){
int num = array[i];
System.out.println(num);
}

投稿2015/03/23 21:03

albacrow

総合スコア31

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

0~9までの数が入った配列を用意し、そこからランダムな場所を抜き取ってつかったらどうですか?

投稿2015/03/23 20:55

chokojori

総合スコア973

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Ryzna

2015/03/24 01:10

おそらくその「ランダム」が実現できるならそもそも乱数が問題なく生成できているのだと思われますorz
chokojori

2015/03/24 01:29

え? そのレベルの話? ここでいう重複なくっていうのは、実行の度に違う結果を出すことをより確実にしたいという話ではなく、ある実行において一度出た数が二回以上出ないようにするだけでは...
Ryzna

2015/03/24 02:10

「重複しない乱数作るなら配列の要素番号を乱数で指定すればよいのではないか?」という回答に見えたので、そもそもその要素番号をランダムに選択する値が作れるなら乱数が作れたと同義ではないかという意味です。わかりづらくてすみません;
Ryzna

2015/03/24 02:13

ちなみに質問者さんのコードを実行すると5ループのうち、かなり高確率で同じ値が連続して出現します。演算速度が速ければこの確率はあがって行きます。
chokojori

2015/03/24 03:54

「抜き取って」という言い方がわかりにくかったかな。RemoveAtするということです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問