質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.48%
C#

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

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

4回答

1592閲覧

文字列をランダムで作る関数が同じ値を返す

_Beginner

総合スコア103

C#

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

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2019/09/01 11:56

編集2019/09/01 12:31

C#

1//ランダムな文字列を作成 2 private const string CHARS = "0123456789abcdefghijklmnopqrstuvwxyz"; 3 public static string GenerateRandomNumber(int length) 4 { 5 System.Text.StringBuilder sb = null; 6 sb = new System.Text.StringBuilder(length); 7 System.Random r = null; 8 r = new System.Random(); 9 10 for (int i = 0; i < length; i++) 11 { 12 int pos = r.Next(VillagerID_CHARS.Length); 13 char c = CHARS[pos]; 14 sb.Append(c); 15 } 16 17 Debug.Log(sb); 18 return sb.ToString(); 19 }

こちらの関数を使ってランダムな文字列を返そうとしているのですが、
この処理をfor文で呼び出すと必ず同じ文字列が2つ返されます。

C#

1//呼び出しコード 2void Call(){ 3 List<string> str = new List<string>(); 4 for (int i = 0; i < 4; i++) 5 { 6 str[i] = GenerateRandomNumber(5); 7 Debug.Log(str[i]); 8 } 9}

デバッグ結果(1回目)↓

5j2kv

3vk54
4kco8
4kco8

〃(2回目)↓

9l654

lfm34
lfm34
7ght0

など重複するタイミングも毎回違います。

なぜ重複してしまうのでしょうか。何度もコードを見直したのですが見つからなかったので質問しました。
どなたか回答お願いします。

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

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

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

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

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

guest

回答4

0

毎回乱数生成機を r = new System.Random();と生成している

引数なしだとシードを時刻で作る
時刻で作るということは十分高速で処理が走るとシード値が同じになる

シード値が同じだと同じ結果になる

というわけでRandomクラスのインスタンスをメンバで持って一回だけ初期化しましょう

投稿2019/09/01 12:05

ozwk

総合スコア13521

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

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

_Beginner

2019/09/01 12:27

コンピュータの乱数は時刻をもとに計算されているのは知っていたのですが、 そのせいでこうなっていたのですね。 参考になりました。ありがとうございます!
guest

0

System.Random()は、時刻相当をベースに初期化するので、短い間隔で複数回呼ぶと同じ乱数系列になります。
System.Random()は一度だけ呼んで、インスタンスを保存して使いまわすとよいかと思います。
あるいは、毎回異なる引数で呼び出すか。
あるいは、ミリ秒単位でスリープを入れるか。

投稿2019/09/01 12:09

otn

総合スコア84538

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

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

_Beginner

2019/09/01 12:29

異なる引数、スリープ、という手もあるのですね。 今回は初期化を一回だけすることにします。ありがとうございます!
guest

0

確認してませんが、、、

System.Random r = null; r = new System.Random();

関数の中でnewしているので、タイミング次第で、同じ初期値では?
グローバルで、初期化(new)するか、呼び出し側で、初期化し、それを使用するすれば、どうでしょう。

投稿2019/09/01 12:04

pepperleaf

総合スコア6383

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

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

_Beginner

2019/09/01 12:25

なるほど。 グローバルで初期化することにしました。ありがとうございました。
guest

0

ベストアンサー

r = new System.Random();

new を行うことにより、乱数発生ロジックは初期化され、以降、同じ数列を出すことになります。

ということで、その関数の中でnewせず、関数の外で、スタティック変数にしてしまいましょう

それでも、そのプログラム自体の起動時点から同じ文字列が出ることになりますんで、プログラム開始時点で現在日時を取得し、それをもとにnextをループさせましょう

投稿2019/09/01 12:03

y_waiwai

総合スコア87774

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

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

Q71

2019/09/01 12:06

補足 乱数ジェネレーターは、アプリケーションで1つだけ作るようにしましょう。また、スレッドセーフではないので、注意しましょう。詳しいことは、リファレンス(機械翻訳が読みにくいですが)に書いてあります。
_Beginner

2019/09/01 12:25

素早く、わかりやすい回答ありがとうございます! 一番早かったためベストアンサーに選びます。 >>Q71さん 補足ありがとうございます。 こういうものは使いまわしたほうがいいのですね。ありがとうございます。
Zuishin

2019/09/01 12:33

ベストアンサーですが、間違っている、もしくは誤解を招く表現なので低評価しました。 new System.Random() は現在時刻をシードにしますから、最後の一文は冗長です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問