忍者ブログ
バイオインフォマティックス技術者試験、情報処理試験など、IT系の試験を基礎から勉強します。また、Javaなどプログラミングを勉強します。

【VBAスタンダード対策】動的配列を定義する「ReDim」の基本構造を攻略!

サイズが決まっていない「動的配列」は、そのままでは使えません。ReDim ステートメントを使ってメモリ上に領域を確保する際のルールと、実行時に中身がどう変化するかという構造的特徴を確認しましょう。

1. 問題:ReDimによる配列の再定義と初期化

【 問題 】 下記のコードを実行した際、最後のメッセージボックスで表示される値として正しいものはどれでしょうか?

Sub ArrayTest()
    Dim myAry() As Integer ' --- (1) 動的配列の宣言
    
    ReDim myAry(2) ' --- (2) サイズを3つ(0-2)に決定
    myAry(0) = 10
    myAry(1) = 20
    
    ReDim myAry(5) ' --- (3) サイズを6つ(0-5)に変更
    
    MsgBox myAry(0)
End Sub

① 0
② 10
③ 20
④ エラー(実行時エラー)が発生する

2. 正解:ReDimによる初期化に関する正解

正解: ① 0

3. 解説:ReDimは「箱の作り直し」である

動的配列を使う上で、ReDim がメモリに対してどのような操作を行っているか、その構造的な動きを理解することが重要です。

[ ReDimの構造的プロセス ]

1. 宣言時:Dim myAry()
「動的配列を使うよ」という名前だけの登録です。中身は空っぽで、このまま myAry(0) = 1 と書くとエラーになります。

2. 初回ReDim:ReDim myAry(2)
ここで初めてメモリ上に 0, 1, 2 の3つの箱が作られます。

3. 二度目のReDim:ReDim myAry(5)
【重要】 単なる ReDim は、既存の配列を一度破棄し、新しいサイズの配列をゼロから作り直します。
そのため、それまでに代入していた「10」や「20」といったデータはすべて消え去り、数値型なら「0」にリセット(初期化)されます。

1. ここが試験に出る!: 試験では「ReDimをすると既存のデータはどうなるか?」という点がストレートに問われます。「作り直し = 初期化」という構造を即座にイメージできるようにしましょう。
2. エンジニアの視点: 「とりあえず大きく確保し直せばいいだろう」という安易な ReDim は、データ消失のバグを生みます。もしデータを残したいなら、次の次の問題で扱う Preserve キーワードが必要になりますが、まずは「ReDim = リセット」という基本構造を叩き込むのが理系NEOな学習順序です。


4. まとめ

「ReDimは、新しい箱への完全な取り替え」。このルールがあるからこそ、配列のサイズを自由に変えられる柔軟性が生まれます。データが消えるというリスクを正しく把握して初めて、動的配列という強力な武器を使いこなせるようになるのです。


PR

【VBA】脱・ハードコーディング!定数と設定値をスマートに管理する極意

VBAの保守性を下げる最大の要因は、コードの中に直接書き込まれた「値」です。これらを「不変の定数」と「可変の設定値」に切り分け、適切な場所に配置する設計術を整理してみましょう。

1. 定数(Const):コードに刻む「不変のルール」

プログラミングにおける定数とは、システムのロジックそのものを支える「物理法則」のようなものです。これらは標準モジュールで一括管理するのが鉄則です。

[ 性質 ]:コンパイル時に確定し、プログラム実行中に変更できない。
[ 管理場所 ]:専用の標準モジュール(例:MConst)に Public Const で集約。
[ 用途 ]:数学的な定数(円周率)、エラーコードの定義、1週間の日数など。

2. 設定値(Settings):外に出すべき「可変のデータ」

ポイント:ロジック(VBA)とデータ(設定)を分離する

「保存先パスが変わった」「税率が変わった」だけでVBAプロジェクトを解いてコードを修正するのは非効率です。これらはコードの外(シートや外部ファイル)に追い出し、実行時に読み込む設計にします。これにより、開発者以外でも安全に挙動を調整できるようになります。

3. 進化した定数管理の構成図

理想的な構成は、管理レベルに応じて「内部管理」と「外部管理」を使い分けるハイブリッド型です。

[ 管理レベル別の格納場所 ]

Lv.1: 固定値(コード内のConst)
数学的定数など、アプリの根本ルール。

Lv.2: 準固定値(専用の標準モジュール)
開発者だけが把握していれば良い内部定数(アプリ名称など)。

Lv.3: 設定値(Excelの隠しシート)
運用担当者が変更する可能性のある値(税率、フォルダパス)。

Lv.4: 環境依存値(外部ファイル / 環境変数)
実行環境(開発機・本番機)で変わる値(DB接続先、ログ出力先)。

4. エンジニアの視点:なぜ「外部化」が必要なのか?

1. 判断の基準: 「その値を変えるとき、ロジックの修正が必要か?」と考えます。単なるパラメータの変更なら「設定値(外部)」、プログラムの挙動そのものの定義なら「定数(内部)」です。
2. 保守性の違い: すべてを Const で書くと、環境移行や年次更新のたびに開発者の工数が発生します。設定値をシート等に逃がすことで、現場で完結する「自走するツール」になります。
3. 美しさの正体: 定数を直す際にコードを触らない設計は、オブジェクト指向における「依存性の注入(DI)」の第一歩です。クラスモジュール等で設定読み込みを隠蔽すれば、メインロジックは常にクリーンな状態を保て、まさに「いけいけ」なコードになります。


5. まとめ

内部定数(Lv.1-2)でシステムの堅牢性を保ち、外部設定(Lv.3-4)で運用上の柔軟性を保つ。この2軸を意識するだけで、あなたのVBAツールは劇的にメンテナンスしやすくなります。「定数を直すためにコードを開かない」——そんなスマートな設計を目指しましょう。




【VBA】再帰関数で解くフィボナッチ数列!数学的定義をそのままコードにする美学

数学的な美しさを持つ「フィボナッチ数列」。前の2つの数字を足すと次の数字になるというシンプルなルールですが、これをVBAで実装する場合、「再帰(Recursive)」という手法を使うと、驚くほど直感的でエレガントなコードになります。

1. 仕様:フィボナッチ数列とは?

以下のルールで並ぶ数字の列です。プログラミングでは、n番目の数字を求める関数を作成するのが一般的です。

[ ルール ]
・0番目は 0、1番目は 1
・n番目は「(n-1)番目 + (n-2)番目」

[ 数列の例 ]
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...

2. アルゴリズム:自分自身を呼び出す「再帰」の構造

ポイント:n=0 または 1 の時は、決まった値を返す

再帰関数とは、関数の中で自分自身を呼び出す手法です。フィボナッチの定義 $F(n) = F(n-1) + F(n-2)$ をそのまま記述できるのがメリットですが、無限に呼び出し続けないよう、n=0 や n=1 の時は計算せずにその値を返すというルールを最初に記述するのが鉄則です。

[ 具体的な動作フロー(n = 4 の場合) ]

Step 1: Fib(4) を呼び出し
Fib(3) + Fib(2) の計算を開始。

Step 2: 枝分かれ
Fib(3) はさらに Fib(2) + Fib(1) に分解される。

Step 3: 最小単位への到達
分解を繰り返し、nが 1 や 0 に到達したら、決まった値(1 や 0)を返す。

Step 4: 合流
返ってきた数値が足し算されながら親へ戻っていき、最終的な答え(3)が導き出される。

3. サンプルコード(そのままコピーOK)

Functionの中で自分自身を呼び出している点に注目してください。非常にスッキリとした記述になります。

' フィボナッチ数を求める再帰関数
Function Fibonacci(n As Long) As Long
    If n <= 0 Then
        Fibonacci = 0                   ' 0の時は0を返す
    ElseIf n = 1 Then
        Fibonacci = 1                   ' 1の時は1を返す
    Else
        ' 自分自身を呼び出して足し算する(再帰)
        Fibonacci = Fibonacci(n - 1) + Fibonacci(n - 2)
    End If
End Function

' 実行用プロシージャ
Sub RunFibonacci()
    Dim i As Long
    For i = 0 To 10
        Debug.Print Fibonacci(i)
    Next i
End Sub

4. 実行結果

イミディエイトウィンドウには、加算の連鎖によって生成された数列が次のように表示されます。

0
1
1
2
3
5
8
13
21
34
55

1. 技術的な補足: 再帰はコードが短くなる一方で、n が大きくなると計算回数が爆発的に増えるという弱点があります。VBAで n = 40 を超えると処理が極端に重くなるため、大きな値を扱う場合は、以前紹介したループ処理で積み上げる方が実用的です。
2. エンジニアの視点: 再帰は「分割統治」というアルゴリズムの基本思想を学ぶのに最適です。Javaなどのモダンな言語でも使われる手法ですが、VBAでこれをサラッと実装できると、論理的思考ができる「いけいけ」なエンジニアとして一目置かれること間違いなしです。


5. まとめ

「n=0, 1ならこの値を返す」という基本さえ押さえれば、複雑な計算も再帰でシンプルに記述できます。フィボナッチ数列のように、定義がそのまま形になるプログラミングの快感をぜひ味わってみてください。用途に応じてループと再帰を使い分けられるようになれば、あなたのエンジニアとしての引き出しは確実に増えるはずです。




【VBA】If文を減らしてスマートに解く!FizzBuzz問題のエレガントな解法

プログラミングの入試問題とも言われる「FizzBuzz」。単純に条件分岐を重ねるだけでも解けますが、コードの美しさと拡張性を意識すると、全く違ったアプローチが見えてきます。今回は、VBA特有の文字列結合を活かした、If文の少ないスッキリとしたコードを解説します。

1. 仕様:FizzBuzz問題のルール

1から指定した数まで順番に数字を数え上げ、以下の条件に従って値を出力します。特に「15のとき」をどう処理するかが、If文を減らす鍵となります。

[ ルール ]
・3の倍数なら 「Fizz」
・5の倍数なら 「Buzz」
・両方の倍数(15の倍数)なら 「FizzBuzz」
・それ以外は 「その数字」 をそのまま表示

2. アルゴリズム:文字列結合による「条件分岐の集約」

重要ポイント:空文字変数に「付け足していく」発想

「15の倍数」を独立した条件として判定するのではなく、3の判定結果と5の判定結果を「結合」させることで、複雑なElseIfを排除します。最後に、変数の中身が空かどうかで数字を表示するか判定するだけの、極めてシンプルな構造です。

[ 具体的なロジック(i = 15 の場合) ]

Step 1: 初期化
変数 res を空にする。

Step 2: 3の倍数判定
15は3で割り切れるので、res に "Fizz" を代入(結合)。

Step 3: 5の倍数判定
15は5でも割り切れるので、res に "Buzz" を追加結合。
結果、res は "FizzBuzz" になる。

Step 4: 最終判定
res が空でないのでそのまま出力。もし空なら数字を出力。

3. サンプルコード(そのままコピーOK)

イミディエイトウィンドウに出力する、If文の使用を最小限に抑えたエレガントな実装例です。

Sub ElegantFizzBuzz()
    Dim i As Long
    Dim res As String

    For i = 1 To 30
        res = "" ' 変数をリセット

        ' 3の倍数なら文字を入れる
        If i Mod 3 = 0 Then res = "Fizz"

        ' 5の倍数なら文字を「付け足す」
        If i Mod 5 = 0 Then res = res & "Buzz"

        ' 文字が入っていればそれを、空なら数字を表示
        Debug.Print IIf(res <> "", res, i)
    Next i
End Sub

4. 実行結果

上記コードを実行すると、イミディエイトウィンドウには以下のように出力されます。15と30の箇所が正しく「FizzBuzz」になっているのが分かります。

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz
Fizz
22
23
Fizz
Buzz
26
Fizz
28
29
FizzBuzz

1. 技術的な補足: IIf 関数(Immediate If)を使用することで、条件出力を1行に集約しています。また、3と5の判定を独立させることで、「15のときは…」という重複した条件式を書く必要がなくなり、コードの「DRY(Don't Repeat Yourself)」原則を守っています。
2. エンジニアの視点: この手法は、将来的に「7の倍数のときはWoof」といった条件が追加されても、If文を1行足すだけで対応できる「拡張性」に優れています。多分岐を力技で書くのではなく、データの流れ(パイプライン)を作るような意識で書くのが「いけいけ」なエンジニアへの近道です。


【VBA】標準モジュール vs クラスモジュール:違いと使い分けの極意を徹底解説!

VBAをステップアップさせる鍵は、2つのモジュールの使い分けにあります。「いつものSub/Function」と「設計図としてのクラス」、それぞれの特徴を整理してみましょう。

1. 標準モジュール:どこでも使える「道具箱」

VBAを始めたときに書くコードのほとんどはここに入ります。「どこからでも呼べる関数や変数を置いておく場所」であり、特定の対象に縛られない汎用的な処理に向いています。

[ 特徴 ]
★ 性質:常にメモリ上に存在し、呼び出せばすぐに動く。
★ 状態:データの保持には不向き。変数は全体で共有されるため、意図しない書き換えのリスクがある。
★ 用途:マクロ記録の保存先、共通の計算(消費税計算など)、メインの実行フロー。

2. クラスモジュール:個性を生み出す「設計図」

こちらは「新しい『モノ(オブジェクト)』の作り方を定義する場所」です。実体(インスタンス)を生成して初めて機能する、プロフェッショナルな開発には欠かせないモジュールです。

ポイント:インスタンスごとに別々のデータを保持できる

例えば「Logger(記録係)」というクラスを作れば、ファイル出力用のLogger A、画面出力用のLogger Bといった具合に、同じ設計図から「個性の違う部品」を複数生み出せます。

3. 実践比較:コードで違いを体感する

【標準モジュール:誰でも使える「道具」】
' 名前を呼ぶだけで即実行可能
Public Sub CalcTax(price As Long)
    MsgBox "税込価格は " & price * 1.1 & " 円です"
End Sub

【クラスモジュール:生み出して使う「部品」】
' クラス名: clsLogger
Private pName As String
Public Property Let LoggerName(val As String)
    pName = val
End Property
Public Sub Log(msg As String)
    Debug.Print "[" & pName & "] " & msg
End Sub

【呼び出し側:Newで実体化して個性を与える】
Sub Test()
    Dim logA As New clsLogger
    logA.LoggerName = "ファイル出力係"
    
    Dim logB As New clsLogger
    logB.LoggerName = "画面表示係"
    
    logA.Log "保存完了" ' 結果:[ファイル出力係] 保存完了
    logB.Log "保存完了" ' 結果:[画面表示係] 保存完了
End Sub

4. エンジニアの視点:どちらを選ぶべきか?

1. 判断の基準: 処理の「手順」や「共通の計算」をまとめたいなら標準モジュール、データと処理をセットにした「役割を持つ部品」を作りたいならクラスモジュールを選びます。
2. 保守性の違い: 大規模な開発では、何でも標準モジュールに書くとコードがスパゲッティ状態になります。役割ごとにクラス化(カプセル化)することで、影響範囲が限定され、修正に強い「いけいけ」なシステムが構築できます。
3. Javaエンジニアの感覚: 標準モジュールは static メソッドが集まった Utility クラス、クラスモジュールは通常の Class 定義そのものだと考えると、その設計意図がスッキリ理解できるはずです。


5. まとめ

最初は標準モジュールだけで十分かもしれません。しかし、複雑なツールを作る際には「これは何かの役割(クラス)にできないか?」と考える癖をつけてみてください。クラスモジュールを使いこなせたとき、あなたのVBAは単なる自動化ツールから、洗練された「ソフトウェア」へと進化します。


        
  • 1
  • 2
  • 3