質問: a(0) End Sub ``` ![イメージ説明](https://teratail.storage.googleapis.com/uploads/contributed_images/8309d986cdd15c6b49d2d93e8cb2b6e9.png)
回答: 変数とは 変数とは、値を格納しておく入れ物です。よく箱などに例えられます。 一口に箱といっても色々な種類があり、目的によって使い分けられます。 塩には塩の入れ物、醤油には醤油の入れ物があるように、変数も入れる物(数値・文字列・セル範囲)によって使い分けます。 これが変数の型です。 配列とは 配列とは、同じ箱を複数セットで用意するようなものです。 例えば `Dim A(10) As String` とすると文字列を入れる箱Aが10個用意され、それぞれの箱に違う値を入れることができます。 ``` A(0)="れもん" A(1)="いちご" ・・・ A(9)="きうい" ``` 多次元配列とは 多次元配列とは、配列をさらにグループ分けして管理したいときに使います。 例えば `Dim A(3, 10) As String` とすると文字列を入れる箱Aが10x3個用意されます。 ``` 'グループ0にはかな名を格納 A(0, 0)="れもん" A(0, 1)="いちご" A(0, 9)="きうい" 'グループ1には漢字名を格納 A(1, 0)="檸檬" A(1, 1)="苺" A(1, 9)="彌猴桃" 'グループ2には単価表示を格納 A(2, 0)="\200" A(2, 1)="\500" A(2, 9)="\300" ``` といった具合に使えます。 上記は2次元配列ですが、さらに3次元、4次元とグループ分けすることもできます。 当然ですが、高次元配列になるほど複雑になるので管理が大変になります。 アドバイス 今回やりたいことは、正直いうと配列を使うほどのことではありません。 おそらく学習のために敢えて配列を使用しているものと思いますので、配列を使う前提は崩さずにアドバイスさせていただきます。 まず他の方からも指摘があるとおり、いくつかバグといえる部分が存在します。 1条件を満たさないとカウンタをインクリメントしない ⇒カウンタのインクリメントは条件文の外で行う必要があります。 2複数セルを指定したRangeからValue取得している ⇒複数セルを指定した場合、Range.Valueは取得できません。範囲内のセルのそれぞれの値はRange.Value2に配列として格納されています。 3ループ6周目ではじめて"No"を見つけた場合でも、a(6)に値をセットしている。 ⇒出力時はa(0)の内容を出力しようとしているので、最初に見つけた"No"の行の内容をa(0)に格納したいのではないでしょうか? 上記1はすぐにも修正できると思います。 しかし23を修正するためには、まず配列でどのように値を管理したいのかを整理する必要がありそうです。 今回の場合、配列で管理したい内容は2種類あります。 1つはセルの値で、これを3列分覚えておきたいものと思います。 その3列1セットの値を、行毎に覚えておきたい、これが2つめの要素です。 実際にそれぞれどう管理するかというと、いくつか方法があります。 例1 1次元配列を3つ用意する 名前の違う配列を3種類用意して、B列・C列・D列それぞれの値を覚えさせる方法です。 ``` Dim b(10) As String 'B列の値格納用の文字列型配列 Dim c(10) As String 'C列の値格納用の文字列型配列 Dim d(10) As String 'D列の値格納用の文字列型配列 Dim iFind As Integer 'Noを見つけた数 Dim c_Cnt As Integer '対象行 iFind = 0 c_Cnt = 2 For i = 0 To 7 If Cells(c_Cnt, "D").Value = "No" Then b(iFind) = Cells(c_Cnt, "B") c(iFind) = Cells(c_Cnt, "C") d(iFind) = Cells(c_Cnt, "D") iFind = iFind + 1 End If c_Cnt = c_Cnt + 1 Next For i = 0 To 7 If d(i) <> "No" Then Exit For '配列dに"No"が格納されていなければループ終了 Cells(11 + i, "B") = b(i) Cells(11 + i, "C") = c(i) Cells(11 + i, "D") = d(i) Next ``` 例2 2次元配列を利用する 2次元配列を1つ用意して、要素1で列を管理する方法です。 ``` Dim a(3, 10) As String '文字列型の2次元配列 Dim iFind As Integer 'Noを見つけた数 Dim c_Cnt As Integer '対象行 iFind = 0 c_Cnt = 2 'チェック For i = 0 To 7 If Cells(c_Cnt, "D").Value = "No" Then a(0, iFind) = Cells(c_Cnt, "B") 'グループ0にはB列の値を格納 a(1, iFind) = Cells(c_Cnt, "C") 'グループ1にはC列の値を格納 a(2, iFind) = Cells(c_Cnt, "D") 'グループ2にはD列の値を格納 iFind = iFind + 1 End If c_Cnt = c_Cnt + 1 Next '出力 For i = 0 To 7 If a(2, i) <> "No" Then Exit For 'グループ2に"No"が格納されていなければループ終了 Cells(11 + i, "B") = a(0, i) Cells(11 + i, "C") = a(1, i) Cells(11 + i, "D") = a(2, i) Next ``` 例3 配列に文字列ではなくRangeオブジェクトを格納する 配列の管理を検討する上で例12はある意味正攻法なやり方ですが、ここで紹介する方法はRangeオブジェクトの.Value2に欲しい3つの値がそろっていることを利用したExcel特化の方法です。 持っている情報をうまく使えば管理が簡単になる例としてご紹介します。 ``` Dim a(10) As Range 'Range型の配列 Dim iFind As Integer 'Noを見つけた数 Dim c_Cnt As Integer '対象行 iFind = 0 c_Cnt = 2 'チェック For i = 0 To 7 If Cells(c_Cnt, "D").Value = "No" Then Set a(iFind) = Range(Cells(c_Cnt, "B"), Cells(c_Cnt, "D")) '配列にB列~D列のRangeを格納 iFind = iFind + 1 End If c_Cnt = c_Cnt + 1 Next '出力 For i = 0 To 7 If a(i) Is Nothing Then Exit For '値が格納されていなければループ終了 Range(Cells(11 + i, "B"), Cells(11 + i, "D")).Value2 = a(i).Value2 '3列分の値がまとめて.Value2に格納されているので、これを出力する Next ``` 長くなってしまいましたが、以上です。 参考になれば幸いです。