3
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Excel VBAAdvent Calendar 2017

Day 25

Excelで関数型プログラミングに目覚めたかもしれない。(応用編)

Last updated at Posted at 2017-12-17

前回書いた基礎編の続きです。実際に、業務アプリを書く場合を例に説明していきます。

ロット番号をMATCHする。

前提として、金属加工業で丸鋼からNC旋盤で部品を作成し、工程はロットで管理しているとします。
ロットは、年(4桁)ー機械番号(2桁)ー連番(3桁)とし、Excelのテーブルでデータを管理しています。
テーブル T1_ が検索先、テーブル T2_ を検索元、
ロット番号は、各テーブルの左端に、呼び出される関数はT2_の見出しが
LIの列にあるとし、列全体に関数 =MLOT(T1_,T2_) で埋められています。

Function MLOT(R1, R2)
    MLOT = MP(R1, R2, 3, 3, 0, 0)
End Function

前回定義した、関数MPを使うと簡単ですね。返り値は、検索先データの行数です。行数がわかれば、
検索先からデータを持ってくるには、隣のセルあたりに 関数 =DI(T1_[製品名],[@LI]) 
とかすれば呼び出せるわけです。

3テーブルを使用し同じキーのデータを検索して集める。

実は、1行のテーブルはコントロールレコードとして使用できます。
テーブル T1_を検索先、テーブルT2_を検索キーを含むコントロールレコード、
テーブル T3_を検索結果が入るものとします。T1_,T2の左端は、製造番号(4桁)が入っています。T3_[L]に関数 =MPC(T1_,T2_,T3,1,1) で埋めます。

Function MPC(R1, R2, R3, Optional L = 2, Optional P = 1, Optional M1 = 0, Optional M2 = 1, Optional M3 = 0, Optional S = "") ' MATCH PAIR CHAIN
    On Error Resume Next

    M3 = IFZS(M3, MM(R3))
    M1 = IFC(M3 = 1, M1, DI(R3, M3 - 1))
    S = MP(R1, R2, L, P, M1, M2)
    
    MPC = S
End Function

T3_[L]には、検索先の同じ製造番号の行数が表示されます。
後は、T3_[製品名] に関数 =DI(T1_[製品名],[@L])を埋めていくなどして
データを引っ張っていきます。

同一列で同じキーのデータを検索する。

上ではテーブルを3つ使いましたが、同一列の場合に、列下の同一キーデータの場合はどうでしょう。簡単ですね。

Function MD(R, Optional L = 0, Optional P = 1, Optional M1 = 0, Optional M2 = 0, Optional S = "")
    On Error Resume Next
    Dim V: V = MV(R, M2, L, P)
    M1 = M2
    S = MLOOP(R, R, M1, M2, L, P, V)
    MD = IFC(S = M2, "", S)
End Function

小技1 連続した列のデータを取ってきて縦に並べる。

T1_は、検索先のテーブルで、T2_ にデータを受けます。
列[A]に関数 =DIJ(T1_[[D]:[K]],[A],3) を埋めると、取ってきたデータが
縦に並びます。

Function DIJ(R1, R2, I) 
    DIJ = DI(R1, I, MM(R2))
End Function

小技2 Rangeを配列に格納して返す。

Function AR(R, Optional M = 0, Optional N = 0, Optional S = "")
    On Error Resume Next
    M = IFZS(M, MM(R))
    N = IFZS(N, R.Rows.Count)
    ReDim S(1 To N): Dim J: For J = 1 To N: S(J) = DI(R, M, J): Next J
    AR = S
End Function

Function AC(R, Optional N = 0, Optional M = 0, Optional S = "")
    On Error Resume Next
    M = IFZS(M, R.Columns.Count)
    N = IFZS(N, NN(R))
    ReDim S(1 To M): Dim I: For I = 1 To M: S(J) = DI(R, I, N): Next I
    AC = S
End Function

小技3 配列振分サブルーチン

配列からデータを複数の変数に割り当てます。
日報データを作成するときに使った技で、テーブル列の追加、変更に対応できて便利です。

 CALL DD(AR(R,N),年,機械,連番,製品番号,製品名) 

という風に使用します。

Sub DD(AA, ParamArray AP())
    Dim J: For J = 0 To UBound(AP)
        AP(J) = AA(J + 1)
    Next J
End Sub

最後に

訂正依頼ありがとうございました。
VSCODE からコピーしてペッタンしているのですがまだ慣れていません。

VBA は、普通でない使い方をすると、結構バグがあるようです。
Offset,Resize を誤って使うとハングまたはファイルを壊すし、
テーブルは、Rangeではなく ListObjects らしいのに、Rangeで扱えてしまうとか、
引数で as Range を付けるとエラーになるとか、
場合によって関数IFCがエラーになるのでIF文を使わざるを得ないとか、
再計算の実行順序が保証されてないのに関数 MPC が正しく動作するとか、
いろいろと謎があります。

簡単な実験をするには、Excelは最適なので楽しいです。

テーブルと構造的参照は、新しく入った概念なので、安定するには時間がかかるのでしょう。
VBA も継ぎ接ぎされているので、M言語がユーザ定義関数として使えればいいのでしょうかね。
次はM言語について書く予定です。

ではでは。

3
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?