ここから本文です

VBAで英単語データからランダムに単語テストを作成するマクロを作ったのですが...

cha********さん

2014/5/2509:48:16

VBAで英単語データからランダムに単語テストを作成するマクロを作ったのですが、エラーがでます・・・ご確認していただけないでしょうか。

ご覧いただきありがとうございます。

worksheetは
data question answer
の3枚あります。

dataは2行目より
B列 レベル(3段階でそれぞれ1,2,3の整数が入力されています)
C列 単語
D列 意味
で、今回のマクロではこの単語リストのレベル1のものから重複を避けてランダムに10個の英単語を選び、questionシートに記入する予定です。

questionは3行目より
C列 単語

answerh3行目より
C列 単語
D列 意味
を記入したいです。
エラーが出てしまうので訂正箇所をご指摘いただければ幸いです。
よろしくお願いします。


Sub basic()

Dim a(1900) As Integer
Dim b(1900) As Integer
Dim c(10) As Integer
Dim n As Integer
Dim m As Integer
Dim r As Integer
Dim s As Integer
Dim word(10), meaning(10) As String
Dim data, question, answer As Worksheet


n = 1
m = 1
r = 1
Worksheets("data").Activate
For n = 1 To 40
a(n) = Cells(n + 1, 2).Value
If a(n) = 1 Then
b(m) = n + 1
m = m + 1
End If
Next n
For r = 1 To 10
c(r) = Int(m * Rnd + 1)
If r > 1 Then
For s = 1 To r - 1
If c(r) = c(s) Then
r = r - 1
End If
Next s
End If
word(r) = Cells(b(c(r)), 3).Value
meaning(r) = Cells(b(c(r)), 4).Value
Worksheets("question").Activate
MsgBox word(r)
Cells(r + 2, 3).Value = word(r)
Worksheets("answer").Activate
Cells(r + 2, 3).Value = word(r)
Cells(r + 2, 4).Value = meaning(r)
Next r

End Sub

閲覧数:
828
回答数:
2
お礼:
100枚

違反報告

ベストアンサーに選ばれた回答

blu********さん

2014/5/2512:38:35

修正ではなく、別の方法です。
重複しない乱数の場合は、配列ではなくCollectionを使うと、一度使ったものはRemoveで削除する事が出来るので、プログラムが楽になると思います。
レベルと問題数を指定できるように変数にしています。


Sub sample()
Dim l As Integer
Dim n As Integer
Dim co As Collection
Dim lastRow As Long
Dim r As Long
Dim i As Integer
Dim p As Integer
'
l = 1 '対象レベル
n = 5 '問題数
Set co = New Collection 'Collectionオブジェクト(重複を避けてランダムに選ぶため)
lastRow = Sheets("data").Range("C" & Rows.count).End(xlUp).Row '"data"シートのC列(単語)の最終行
'Sheets("question").Range("C3").Resize(n, 2).ClearContents '"question"シートクリア(必要なら)
'Sheets("answer").Range("C3").Resize(n, 2).ClearContents '"answer"シートクリア(必要なら)
'対象レベルの行を抽出
For r = 2 To lastRow '"data"シートの2行目からC列最終行まで
If Sheets("data").Range("B" & r).Value = l Then '"data"シートのB列(レベル)の注目行が対象レベルなら
co.Add r 'コレクションに注目行を記憶(単語と意味を覚えなければいけないので、対象行を記憶)
End If
Next
'問題表示
For i = 1 To n 'n個(10個)出題
If co.count = 0 Then Exit For 'もしコレクション内にデータが無かったら中止(対象レベルの問題が10問無かったらエラーになるのでそれを回避)
p = Int(Rnd * co.count) + 1 '1からコレクションの個数までの乱数
r = co(p) 'コレクション内のp番目の値(対象レベルの行番号)
Sheets("question").Range("C" & i + 2).Value = Sheets("data").Range("C" & r).Value '"question"シートのC列に"data"シートのC列(単語)のランダム行(r行)の値を表示
Sheets("answer").Range("C" & i + 2).Value = Sheets("data").Range("C" & r).Value '"answer"シートのC列に"data"シートのC列(単語)のランダム行(r行)の値を表示
Sheets("answer").Range("D" & i + 2).Value = Sheets("data").Range("D" & r).Value '"answer"シートのC列に"data"シートのD列(意味)のランダム行(r行)の値を表示
co.Remove p 'コレクション内のp番目のデータは一度使ったので削除(配列ではできない)
Next
End Sub

この質問は投票によってベストアンサーに選ばれました!

ベストアンサー以外の回答

1〜1件/1件中

why********さん

2014/5/2516:15:33

基本ロジックを考え直したらうまくゆくと思います。
投稿のプログラムは修正しきれない論理的バグがあります。
直接てきには b(c(r))=0 になってしまうからですゆえにcells(0,3)は無理
Step実行してみてください。
あと基本はワークシートにアクセスする場合イチイチActivateすると画面がちらつくし処理もおそくなります。転機終了後に転記先シートをActivateするのが良いと思います。
変数や、シートオブジェクトは面倒でもきっちり判り易く定義してプログラムを読みやすくするのがバグを減らすことにつながります。
配列は固定数で定義せずに、動的に必要なだけ確保したほうがベストです。
そのための数値材料は データの有効行数、有効列数になります。
’Excel2003、2007以降では最大行が異なるので以下のようにして互換保持します
MaxR = shd.cells(shd.cells.rows.count,2).end(xlUP).row -1 とか
’Filterがかかってない状態でかつ中途行に空白行がない場合は
MaxR = shd.cells(2,2).Currentregion.Rows.Count -1 などどします。

Dim wb As Workbook
Dim shd As worksheet
Dim shAns As Worksheet
Dim shQue As Worksheet
Dim MaxR As Long
Dim DAT As Variant '後で配列になる

Set shd = wb.Sheets("data")
Set shAns As Sheets("answer")
Set shQue As Sheets("question")

’B2 より実データがあるとすれば最大有効行MaxRは
MaxR = shd.cells(shd.cells.rows.count,2).end(xlUP).row -1 ’です
'ここ場合は列はD列までなので
DAT = shd.Range("$B2:" & "$D" & MaxR)

これで最初の見出し除くデータは
DAT(1,1)がレベル数字
DAT(1,2)が単語文字列
DAT1,3)が意味
として参照できます。DAT(r,c)のr,c部分をFor文で参照します
また、shAnsに転記する場合は shAns.range("B2:D2")=DAT
とすれば、レベル、単語、意味のコピペと同じことができ超高速で転記します。
乱数は e =Application.WorksheetFunction.RandBetween(1,ubound(DAT))
で得て DAT(e,1),DAT(e,2),DAT(e,3)を参照したらいかがでしょうか
重複管理は 重複(ubound(DAT))で配列作成して転記したらTrueにしておき、転記前に参照してTrueなら転記しない とすればいいと思います
重複配列の要素番号はDATと同じなので管理しやすく判りやすいプログラムに
なります。条件 Option Base 1 をGeneralに記述済の場合
あと転記先の行番号は最初は3なので転記後+1 して変数で管理しましょう。
実際のコーディングはご自分で考えてみてね。

みんなで作る知恵袋 悩みや疑問、なんでも気軽にきいちゃおう!

Q&Aをキーワードで検索:

Yahoo! JAPANは、回答に記載された内容の信ぴょう性、正確性を保証しておりません。
お客様自身の責任と判断で、ご利用ください。
本文はここまでです このページの先頭へ

「追加する」ボタンを押してください。

閉じる

※知恵コレクションに追加された質問は選択されたID/ニックネームのMy知恵袋で確認できます。

不適切な投稿でないことを報告しました。

閉じる