- ベストアンサー
重複しない乱数を作り配列に入れる(AS3.0)
- AS3.0で重複しない乱数を生成して配列に格納する方法について質問があります。
- 質問者はFlash Pro CS5を使用しており、以下のコードを実行した結果、一部の数字が抜けていることに気付きました。
- 質問者はMath.floor(Math.random()*(maxN+1-j))の部分に問題があるのか疑問に思っています。また、他の方法があるのかも知りたいと思っています。
- みんなの回答 (1)
- 専門家の回答
質問者が選んだベストアンサー
その式ですと、乱数の範囲が、配列変数のインデックス(管理番号)の最大値よりも 1 だけ広くなってしまいます。 RandomInt 関数内の乱数を求める式を Math.floor( Math.random() * ( maxN - j ) ); に、変更してみてください。 たった 1 の違いが、何が問題なのかと言いますと。 ご提示の式ですと、0 ~ 配列変数の要素の総数、の範囲で乱数を求めることになります。 例えば int_a が 10 個の要素を持っている時、0 ~ 10 までの乱数を求めてランダムに要素を1つ取るとすると、最大の 10 が出た時には int_a[ 10 ] を取ることになります。 しかし、配列変数のインデックスは 0 から始まるので int_a は 0 から 9 番までしかなく、10 番を指定したのでは値の取得に失敗してしまいます。 関数内で、乱数で選んだインデックス(変数 int_r )と int_a の要素の総数を表す a_length の値を監視してみると分かるのですが、値の取得に失敗して「 ,, 」と歯抜けになるのは乱数(= int_r )と a_length が同じになった場合で、運よく1度も同じにならなかった時はこの問題は起こりません。 - - - - - Math.random で任意の範囲の乱数を発生させる式が、Adobe 社のホームページで紹介されています。 ・Math.random() でランダムな整数を取得する方法 http://kb2.adobe.com/jp/cps/228/228622.html ご参考になさった作例では、この式を利用して配列変数 int_a のインデックスの範囲内で乱数を決めて任意の要素を1つ抜き取り、それを別の配列変数 int_b の先頭から順に詰めていく、といった方法をとっていると思われます。 int_a の要素は最初は変数 maxN と同じ数、ご提示のスクリプトですと 10 個あるのですが、配列変数のインデックスは 0 から始まるので、最後の要素は int_a[ 9 ] です。 ですから、抜き取る要素を決める乱数は 0 ~ 9 の範囲で求めます。最大値の 9 とは、maxN - 1 のことです。 すると、先の式に当てはめますと、 Math.floor( Math.random() * ( ( maxN - 1 ) - 0 + 1 ) ) + 0 これを整理しますと、 Math.floor( Math.random() * maxN ); になります。 int_a から splice メソッドで要素を抜き取ると配列変数の要素が少なくなっていきますから、要素が減った分だけ乱数の範囲も狭めていかなければなりません。 抜き取ってなくなった数は、値を抜き取った時にカウントを取っている変数 j を見ると分かります。 合わせますと、int_a の 0 ~最大インデックスの間で乱数を求める式は Math.floor( Math.random() * ( maxN - j ) ); となります。 * * * 今回の件での変数 maxN とは、初期状態の int_a の要素の総数と同じ意味です。 配列変数の要素の総数は length プロパティに記録されており、要素を削除・追加した時には length プロパティは自動的に修正されます。 この点を利用して、 (↓ 各行頭に全角のスペースが入っています。コピーする際はご注意ください) //*** //抜き取った値をint_bに詰める時のインデックス var j:Number = 0; //int_aの要素が尽きるまでループ while( int_a.length ) { //抜き取る要素をランダムに選ぶ var int_r:Number = Math.floor( Math.random() * int_a.length ); //int_aの要素を抜き取り、int_bの先頭から詰めていく int_b[ j ] = int_a.splice( int_r , 1 ); //値を詰めるインデックスを更新 j++; } //*** と、書くこともできます。 なお、繰り返しますが、配列変数のインデックスは”0 から”始まり、最後は”要素の総数 - 1 ”です。 配列変数 int_b の値を for ループで全部取り出す時は、 for( i = 0 ; i < int_b.length ; i++ ) というように書きます。 先頭は1番ではありませんので、ご注意ください。
お礼
丁寧でわかりやすい解説ありがとうございました。 別の書きかたでのコードも大変参考になりました。 for( i = 0 ; i < int_b.length ; i++ ) の部分ですが,どうしても配列の0番目からではなく1番目~10番目に格納したかったので そのように記述してしまいました。 しかし0~9番目に入れて後で新しい配列に入れなおせばよかったのですね。 ありがとうございました。