人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

1から10までの乱数を重複なしで表示する。エクセルVBA
単語テストなどをするときに、単語の順番を変えて出すような場合です。
問題は10問ですが、あらかじめ問題はあるので順番を変えればいいので
シャッフルなのかもしれません。
インターネットではいろいろな質問や回答がたくさんあったのですが、
分かりづらいこともあったので自分なりに作ってみました。
一応動くのですが、これでいいのでしょうか?
より良い方法があればお教えください。
とりあえず、作ったコードを下に書いておきます。

<コード>
Sub ransuu()
Dim ransuu(10) As Integer
Dim i As Integer
Dim j As Integer
Dim k As Integer

For i = 1 To 10
ransuu(i) = Int(Rnd() * 10) + 1
For j = 1 To i - 1
If ransuu(i) = ransuu(j) Then Exit For
Next j
If j < i Then i = i - 1
Next i
For k = 1 To 10
Cells(k, 1).Value = ransuu(k)
Next
End Sub

●質問者: twinkle123
●カテゴリ:コンピュータ 学習・教育
✍キーワード:as EXIT NeXT sub VBA
○ 状態 :終了
└ 回答数 : 4/4件

▽最新の回答へ

1 ● きゃづみぃ
●50ポイント

1番目から順に乱数で取得した値をセットしているんですね。

それで 既にある場合は 飛ばして 次の値をセットしているんですね。

これだと どれだけランダムになるのかが 難しいところです。

こうやって 1から10までセットして次は その配列を シャッフルしたらいいでしょう。

つまり 乱数で 取得した 二つの値の 配列を 入れ替えるのです。

乱数で 3と5を取得した場合、3と5に入っている値を 交換します。

これを 大量回数(これも乱数で取得)やれば けっこう ランダムになるかなと思います。

◎質問者からの返答

すごく速い回答ありがとうございます。

やはり、シャッフルすることが必要なのですね。

大量回数というのは10個の数値に対しては100回くらいとかの感じでよいのでしょうか。

シャッフルのやりかたもなんとなく大体分かりました。

試してみます。


2 ● hissssa
●80ポイント ベストアンサー

乱数を作っては「既出かどうか」をチェックされているわけですが、これだと効率は良いとはいえないでしょう。まぁ10個程度ならあまり気にする話ではないですが。

どうせ「1?10が一回ずつ」と決まってるわけですから、配列ransuu(#)には単純に1?10をそのままセットして、そのあとシャッフルする方が効率的です。

for i=1 to 10 ' 配列に1?10を格納

ransuu(i)=i

next

for i=1 to 10 ' 全要素をシャッフル

j=Int(Rnd() * 10) + 1

c=ransuu(i)

ransuu(i)=ransuu(j)

ransuu(j)=c

next

シャッフルするときも、単純に配列すべてを一つずつ、ランダムな位置のものと入れ替えるようにすれば、確実に漏れなくシャッフルできます。

◎質問者からの返答

ご回答ありがとうございます。

シャッフルの具体的なコードも示していただき分かりました。

>配列すべてを一つずつ、ランダムな位置のものと入れ替えるようにす

るということで、もれなくシャッフルできるのですね。

効率が悪いというご指摘ですが、私も、そう思っていました。

また、考え直してみたいと思います。

ありがとうございます。


3 ● deflation
●50ポイント

ご質問のコードで間違いはありません。


ご参考まで、配列 a をシャッフルするサブルーチンを掲げます。

Sub Shuffle(a)
 Dim k, j As Long
 Dim t
 Randomize
 For k = UBound(a) To 0 Step -1
 j = Fix(Rnd * (k + 1))
 t = a(j)
 a(j) = a(k)
 a(k) = t
 Next
End Sub
◎質問者からの返答

ご回答ありがとうございます。

すみません、UBound を知りませんでしたので、調べていました。

配列の格納できる最大値を求める関数と分かりました。

最大値から1ずつ減じてループさせて、乱数を作って、入れ替えをする。

その際、発生させる乱数の最大値も1ずつ減らす。

というふうに解釈したのですが、この場合 重複はしないのでしょうか。

jに同じ数値が発生することはないでしょうか。

素人なので申し訳ありません。お手数かけます。


4 ● TransFreeBSD
●50ポイント

No.3はこれですね。

さらに今回の場合、wikipediaの次の節にある"inside-out"式を使って配列に入れながら混ぜる方法が良いかもしれません。

ransuu(1) = 1
for i=2 to 10
 j=Int(Rnd() * i) + 1
 ransuu(i)=ransuu(j)
 ransuu(j)=i
next

これは下記と等価です

for i=1 to 10
 ransuu(i)=i
next
for i=2 to 10
 j=Int(Rnd() * i) + 1
 t=ransuu(i) ' ransuu(i)はまだ交換した事がないのでiと同じ
 ransuu(i)=ransuu(j)
 ransuu(j)=t
next

これのループを逆に回すとNo.3になり、さらに交換ではなくてセルへの代入にすると下記になります。

for i=1 to 10
 ransuu(i)=i
next
for i=10 to 2 Step -1
 j=Int(Rnd() * i) + 1
 Cells(i, 1).Value=ransuu(j)
 ransuu(j)=ransuu(i) ' ransuu(i)は今後アクセスすることがないので消さなくてもOK
next
Cells(1, 1).Value=ransuu(1)
◎質問者からの返答

ご回答ありがとうございます。

シャッフルについてのいくつかの方法についての説明ありがとうございます。

すべての個数についてシャッフルをするのを、昇順降順があるということですね。

私の場合は、最初から問題が決まっているので、シャッフルすればよかったのだと思いました。

コードも示していただきよくわかりました。

関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ