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

回答の条件
  • 1人5回まで
  • 登録:
  • 終了:2011/06/04 13:11:59
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:hissssa No.2

回答回数428ベストアンサー獲得回数129

ポイント80pt

乱数を作っては「既出かどうか」をチェックされているわけですが、これだと効率は良いとはいえないでしょう。まぁ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

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

id:twinkle123

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

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

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

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

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

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

ありがとうございます。

2011/06/02 18:43:17

その他の回答3件)

id:taknt No.1

回答回数13539ベストアンサー獲得回数1198

ポイント50pt

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

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

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

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

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

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

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

id:twinkle123

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

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

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

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

試してみます。

2011/06/02 18:38:44
id:hissssa No.2

回答回数428ベストアンサー獲得回数129ここでベストアンサー

ポイント80pt

乱数を作っては「既出かどうか」をチェックされているわけですが、これだと効率は良いとはいえないでしょう。まぁ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

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

id:twinkle123

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

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

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

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

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

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

ありがとうございます。

2011/06/02 18:43:17
id:deflation No.3

回答回数1036ベストアンサー獲得回数126

ポイント50pt

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


ご参考まで、配列 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
id:twinkle123

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

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

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

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

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

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

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

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

2011/06/02 19:09:30
id:TransFreeBSD No.4

回答回数668ベストアンサー獲得回数268

ポイント50pt

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)
id:twinkle123

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

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

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

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

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

2011/06/03 14:20:00
  • id:windofjuly
    うぃんど 2011/06/02 18:57:25
    >ご参考まで、配列 a をシャッフルするサブルーチンを掲げます。
     
    相変わらず検索はお得意のようだけど、コピペ元くらいは書こうよ
    http://scripting.cocolog-nifty.com/blog/2008/03/post_b3e1.html
  • id:taknt
    No3のものは 1番から10番まで順番に 乱数で取得した番号のと 交換するだけなので 重複にはならないです。

  • id:twinkle123
    takntさん了解しました。
    ありがとうございます。
    交換だから重複はないですね。

    ただ、交換のために生成する乱数は、重複する場合があると思いますが、そう考えていいのでしょうか。


  • id:taknt
    乱数ですから 前と同じ数字が出てくるのは 仕方ないですね。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません