VBAを用いた集合の理解 ① aは集合Aの要素である

子供から、数学の集合について訊かれた。高校を卒業して三十余年、
「そういえば、そんな話もあったっけ?」
ぐらいの認識だ。

当時は思考も漠としていて、先生たちの話は常に意識の表層を滑り
抜けていた感覚だけが記憶に残っている(=脳に刺さっていない)。
どちらかといえば集合の問題は、

  • よく解らない
  • 苦手

な分野だった。

ところが今になって見てみると、少なくとも当時より容易に理解
できていることに気づく。おそらく日々、これと似たようなもの、
特に「配列」と向き合ってきたことが、理解の一助となっている
に違いない。

ということで今回は、数回に分けて、VBAを用いた集合の理解
に挑戦してみよう。

なおブログの内容によっては、集合の定義から外れる部分もある
と思うが、お遊びということでご容赦願いたい。

改めて高校数学における「集合とは何か」の情報を求めたところ、
こちらにとても分かりやすくまとめられていた。
manabitimes.jp

  • a∈A aは集合Aの要素である
  • a∉A aは集合Aに属さない

ここで集合Aを配列で表すなら、例えばこのようになると考える。

    Dim 果物 As Variant
        果物 = Array("りんご", "みかん", "ばなな")
  • 「りんご」は、配列「果物」に含まれる
  • 「ぶどう」は、配列「果物」に含まれない

と考えれば、なじみ深い。

そこで、含む/含まないを「True / False」(=真/偽)のBoolean型で
返す関数を作ってみよう。

クラスモジュール(MathSet)

まず、クラスモジュール「MathSet」を作成する。「集合」は、英語で
Set だそうな。ややこしくなる、嫌な予感しかしない。とりあえず頭に
「数学の」という意味で「Math」を付けてみた。
f:id:Infoment:20210511211338p:plain

クラスモジュールとしたのは、ほかにも集合に関する関数などをここに
入れ、一まとめにしたかったから。実際は標準モジュールでも構わない。

今回、クラスモジュールに作成した関数がこちら。

Option Explicit

' このクラス内で**Setや**_setと表現されるものはすべて、
' 数学における「集合(set)」を指している。
' ※ややこしいのでご注意ください。

' このクラス内では、集合はすべてn次元配列で表現する。
' 例)集合:果物 = Array("りんご", "みかん", "ばなな")

' 指定文字列が、ある集合の要素であるか否かを返す。
Public Function IsElement(ByVal element As Variant, _
                          ByVal target_set As Variant, _
                       Optional LookAt As XlLookAt = xlWhole) As Boolean
        
    ' 集合ではないものが指定された場合、Falseを返す。
        If Not IsArray(target_set) Then Exit Function
    
    ' 配列内の値と順にelementを照合し、同じものがある時点でTrueを返す。
    ' 従って、この関数はtarget_set内で複数の同じ値が含まれる場合を除外しない。
    Dim a As Variant
        If LookAt = xlPart Then element = "*" & element & "*"
    
        For Each a In target_set
            If a Like element Then
                IsElement = True
                Exit Function
            End If
        Next
        
End Function

部分一致と完全一致の切り替えが可能な点などが、数学の集合とは違うところ。
いずれどこかで役に立つかもと思い、盛り込んでみた。

標準モジュール

それでは早速、テストしてみよう。

Sub test()

    Dim MS As New VBAProject.MathSet
    Dim 果物 As Variant
        果物 = Array("りんご", "みかん", "ばなな")

        Debug.Print "ばなな:" & MS.IsElement("ばなな", 果物)
        Debug.Print "ぶどう:" & MS.IsElement("ぶどう", 果物)

End Sub

結果は ↓ こちら。とりあえず、意図したとおりに動いてくれた。
f:id:Infoment:20210512055912p:plain
※ここで示しているのは、「ぶどうは果物ではない」ということではなく、
 先に定義した「果物」グループのメンバーに「ぶどう」が入っていない
 ということになります。

今回のシリーズは、配列の編集などを多く盛り込みつつも、仕事ではあまり
役に立たなそうな気がする(いつも?)。でも個人的には面白そうなので、
しばらく続けてみようと思う。

参考まで。