配列って言葉はプログラム用語です。英語でArrayです。そのままのArray関数がVBAにもあります。
さて、ワークシートは二次元配列です。プログラムの二次元配列とワークシートの違いは、配列はメモリ内にあり、ワークシートは見えることです。プログラムでは、ワークシートのセルに入れるために2次元配列を返す関数に慣れましょう。という話です。
自作の関数を活かすには、ワークシートのセルは2次元配列と扱うことと配列数式が必要です。
配列って言葉はプログラム用語です。英語でArrayです。そのままのArray関数がVBAにもあります。
さて、ワークシートは二次元配列です。プログラムの二次元配列とワークシートの違いは、配列はメモリ内にあり、ワークシートは見えることです。プログラムでは、ワークシートのセルに入れるために2次元配列を返す関数に慣れましょう。という話です。
自作の関数を活かすには、ワークシートのセルは2次元配列と扱うことと配列数式が必要です。
mySUM関数に続いて第二弾。数式バーにカッコがいっぱい書いてませんか。プログラムだと限界はありませんし、スキルアップになります。
ワークシート関数を数式バーに3つ以上書く力をプログラム開発に向けましょう。プログラムのスキルアップの方が効率的です。
'自作VLOOKUP関数。完全一致専用
Function myLookUp(検索値これは検索範囲の一番左列, 検索範囲 As Range, 列番号 As Long)
Dim ar()
ar = 検索範囲
Dim i As Integer '行だけ
For i = 1 To UBound(ar, 1) '行の処理
If 検索値これは検索範囲の一番左列 = ar(i, 1) Then
myLookUp = ar(i, 列番号)
Exit Function
End If
Next
End Function
'?myLookUp("ken", Range("e4:h12"), 2)
ややこしい関数も自作でいこう!。これは自作でないとできない。それにとっても自由。
'自作VLOOKUP関数
Function myLookUp2(検索値, 検索列番号, 全範囲 As Range)
Dim ar()
ar = 全範囲
Dim i As Integer, j As Integer
ReDim arr(1 To 100, 1 To 100)'10000とかすると飛びます
Dim ii As Integer 'arrの行番号用、列はjを使う
For i = 1 To UBound(ar, 1)
j = 1
If VBA.CStr(ar(i, 検索列番号)) Like 検索値 Then
ii = ii + 1
For j = 1 To UBound(ar, 2)
arr(ii, j) = ar(i, j)
Next
End If
Next
myLookUp2 = arr
End Function
'?myLookUp2("*k*", 3,Range("e4:h12"))(0,0)
以下は、データ作成用。
Sub 表作成()
'
' Macro1 Macro
'
If VBA.MsgBox("選択しているワークシートが無くなります!!!", vbOKCancel) = VBA.vbCancel Then Exit Sub
Columns("A:h").Delete Shift:=xlToLeft
Range("H3").Select
ActiveCell.FormulaR1C1 = "phone"
Range("H4").Select
ActiveCell.FormulaR1C1 = "'0311111"
Range("H5").Select
ActiveCell.FormulaR1C1 = "'0751111"
Range("H6").Select
ActiveCell.FormulaR1C1 = "'061123"
Range("H7").Select
ActiveCell.FormulaR1C1 = "'075222"
Range("H8").Select
ActiveCell.FormulaR1C1 = "'0322222"
Range("H9").Select
ActiveCell.FormulaR1C1 = "'0521111"
Range("H10").Select
ActiveCell.FormulaR1C1 = "'0622222"
Range("H11").Select
ActiveCell.FormulaR1C1 = "'0753333"
Range("H12").Select
ActiveCell.FormulaR1C1 = "'063333"
Range("H13").Select
Range("E3").Select
ActiveCell.FormulaR1C1 = "no"
Range("F3").Select
ActiveCell.FormulaR1C1 = "name"
Range("G3").Select
ActiveCell.FormulaR1C1 = "address"
Range("E4").Select
ActiveCell.FormulaR1C1 = "1"
Range("E4:E10").Select
ActiveWindow.SmallScroll Down:=-6
Range("E4").Select
Selection.AutoFill Destination:=Range("E4:E12"), Type:=xlFillSeries
Range("E4:E10").Select
ActiveWindow.SmallScroll Down:=-9
Range("F4").Select
ActiveCell.FormulaR1C1 = "tom"
Range("F5").Select
ActiveCell.FormulaR1C1 = "ken"
Range("F6").Select
ActiveCell.FormulaR1C1 = "emi"
Range("F7").Select
ActiveCell.FormulaR1C1 = "bob"
Range("F8").Select
ActiveCell.FormulaR1C1 = "bill"
Range("F9").Select
ActiveCell.FormulaR1C1 = "ben"
Range("F10").Select
ActiveCell.FormulaR1C1 = "sam"
Range("F11").Select
ActiveCell.FormulaR1C1 = "may"
Range("f12").Select
ActiveCell.FormulaR1C1 = "ron"
Range("G4").Select
ActiveCell.FormulaR1C1 = "tokyo"
Range("G5").Select
ActiveCell.FormulaR1C1 = "kyoto"
Range("G6").Select
ActiveCell.FormulaR1C1 = "osaka"
Range("G7").Select
ActiveCell.FormulaR1C1 = "kyoto"
Range("G8").Select
ActiveCell.FormulaR1C1 = "tokyo"
Range("G9").Select
ActiveCell.FormulaR1C1 = "nagoya"
Range("G10").Select
ActiveCell.FormulaR1C1 = "osaka"
Range("G11").Select
ActiveCell.FormulaR1C1 = "osaka"
Range("G12").Select
ActiveCell.FormulaR1C1 = "kyoto"
Range("A1").Select
ActiveCell.FormulaR1C1 = "1"
Range("A1").Select
Selection.AutoFill Destination:=Range("A1:F1"), Type:=xlFillSeries
Range("A1:F1").Select
Range("A4").Select
ActiveCell.FormulaR1C1 = "1"
Range("A4").Select
Selection.AutoFill Destination:=Range("A4:A12"), Type:=xlFillSeries
Range("A4:A10").Select
Range("B4").Select
ActiveCell.FormulaR1C1 = "tom"
Range("B5").Select
ActiveCell.FormulaR1C1 = "ken"
Range("B6").Select
ActiveCell.FormulaR1C1 = "emi"
Range("B7").Select
ActiveCell.FormulaR1C1 = "bob"
Range("B8").Select
ActiveCell.FormulaR1C1 = "bill"
Range("B9").Select
ActiveCell.FormulaR1C1 = "ben"
Range("B10").Select
ActiveCell.FormulaR1C1 = "sam"
Range("B11").Select
ActiveCell.FormulaR1C1 = "may"
Range("B12").Select
ActiveCell.FormulaR1C1 = "ron"
Application.CutCopyMode = False
ActiveSheet.ListObjects.Add(xlSrcRange, Range("$E$3:$h$12"), , xlYes).Name = _
"myTable"
End Sub
以下の関数を標準モジュールに書いて、ワークシート関数のようにセルの中に書く。
ThisCellプロパティは、ユーザー定義関数内で使うことで自分セル位置を取得できる。使う場合は、Excel.Application.ThisCellまたはApplication.ThisCellとApplicationを付ける必要がある。型はRangeなのでRow、CollumnやOffsetも使える。
Function myAddress()
myAddress = Excel.Application.ThisCell.Address(0, 0) '0はFalseでも同じ。0が無いと絶対表示$A$1になる
End Function
Function myCells()
myCells = "Cells(" & Excel.Application.ThisCell.Row & "," & Excel.Application.ThisCell.Column & ")"
End Function
Rowは行、Columnは列のこと。
AceitveCellやSelectionもアドレスを表示することができるが、これらは選択しているセルの位置であり、ユーザー定義関数が入っているセルの位置ではない。もし、ActiveCellやSelectionを使うと上図の場合は、セルA1を選択しているので左のmyAddress()は、A1:D5のすべてがA1に、右もすべてCells(1,1)になる。
ユーザー定義関数を作る時に自分のセルを扱いたい場合はThisCellを使う。
VBでは、配列、コレクション、プロシージャも同じ記号の()を使う。ややこしいですね。他の言語では配列は[ ]を使う。
VBAの()の使い方3つ。
ここでは、とりあえず2番目のRangeを説明します。
まず、XXXX(??, ??,??)とカッコを付けると戻り値がある。つまり、変数名=XXXX(??, ??,??)やDebug.Print XXXX(??, ??,??)( Debug.Print の出力が値)ができる。配列も関数も同じような書き方をする。イミディエイトで?とする場合は、戻り値を期待しているので()がいる。「変数=」の右辺に書く場合も変数に代入したいのだから()がいる。
ExcelのオブジェクトであるRange(“A1”)()のカッコは、配列ように見えるがItemの省略。Item関数は感覚的には配列のように考えればいい。以下は、イミディエイトウィンドウで、?はPrintのこと。?から始まる行は入力。次の行は出力結果。
set kk=range("a1:b2")
?vba.TypeName(kk)
Range
?kk(1)
A1
?kk(2)
B1
?kk(3)
A2
?vba.TypeName(range("a1:b2"))
Range
?range("a1:b2").Item(1)=range("a1:b2")(1)
True
?range("a2:b3")(1)
A2
配列でもオブジェクトでも関数でも()のカッコは、戻り値を受け取るためと理解すればいい。最もよく使うのがコレクションの中の一つを取り出すために使う()。
VBAの関数の話しです。
Date関数は時間が無いことがイミディエイトで実行するとわかる。関数の調査ができると例えばHour(Date)は常に0になることが確認できる。 ?から始める文字列の行が入力する。他は出力行。
?vba.Now
2018/08/26 1:16:41
?date
2018/08/26
?vba.Hour(date)
0
?hour(now)
1
Now、Date関数どちらも引数が無い。セルの中で使うワークシート関数のDateは引数がいる。