VBAを用いた集合の理解 ② aを集合Aの要素として追加または除去
昨日から高校数学の学び直しとして、VBAを用いた集合の理解に挑戦している。
infoment.hatenablog.com
今日も、昨日の続きから。
集合の理解といいつつ、二日目にして早くも逸脱する。なぜなら集合を配列で表したため、個人的に要素の追加および削除を機能として盛り込みたくなったから。
そこで前段として、まず「要素を持たない集合(=空集合)」を準備する。
空集合については、こちらを参照されたし。
manabitimes.jp
今回は集合を「配列」と同義に扱っているので、空集合は空配列とすれば
何かと都合がよい。
クラスモジュール(MathSet)
' 空集合(=空配列) Public Property Get EmptySet() As Variant EmptySet = Array() End Property
配列に要素を追加するとなれば、「どこに?」を決める必要がある。
特に多次元配列に於いては、どこに加えるにしてもややこしくなりそうだ。
そこで思い切って、要素の追加及び削除の過程で、配列は全て一次元配列に
変換することにした。今回は一旦すべての要素をコレクションに加えた上で、
一次元配列に変換する。
' コレクションから一次元配列を作成する。 Public Function ToArray(source_col As Collection) As Variant Dim arr() As Variant ReDim arr(1 To source_col.Count) Dim i As Long For i = 1 To source_col.Count arr(i) = source_col.Item(i) Next ToArray = arr End Function
配列では、同じ要素を複数格納することがある。そこで今回は、重複の可否を
切り替えられるようにしてみた。なお、配列内に格納済の要素を追加する際、
要素の重複不可とする場合は、戻り値を空配列にすることとした。
(私的な決め事)。
' 指定文字列が、ある集合の要素であるか否かを返す。 ' a ∈ A:aは集合Aの要素である。 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
' 指定文字列を、ある集合に追加する。 ' ※「ある集合」を強制的に1次元配列とし、その末尾に「指定文字列」を追加。 Public Function AddElement(ByVal element As Variant, _ ByVal target_set As Variant, _ Optional duplicable As Boolean = True) As Variant ' 指定文字列がすでに指定集合(指定配列)に含まれている場合。 If IsElement(element, target_set) Then ' 要素の重複を不可とするならば、空集合(空配列)を返す。 If Not duplicable Then AddElement = EmptySet Exit Function End If End If ' 上記以外の場合、いったん全てコレクションに格納ののち、一次元配列に ' 格納しなおす。 Dim col As Collection Set col = New Collection Dim a As Variant For Each a In target_set col.Add a Next col.Add element AddElement = ToArray(col) End Function
' 指定文字列を、ある集合から除去する。 ' ※「ある集合」は強制的に、一次元配列に変換される。 ' ※「ある集合」に指定文字列が複数ある場合、すべて除去する。 Public Function RemoveElement(ByVal element As Variant, _ ByVal target_set As Variant) As Variant ' 指定文字列が指定集合(指定配列)に含まれていない場合、 ' 空集合(空配列)を返す。 If Not IsElement(element, target_set) Then RemoveElement = EmptySet Exit Function End If ' 上記以外の場合、指定文字を除く配列を作成する。 Dim col As Collection Set col = New Collection Dim a As Variant For Each a In target_set If a <> element Then col.Add a End If Next RemoveElement = ToArray(col) End Function
それでは、テストしてみよう。
標準モジュール
Sub test() Dim MS As VBAProject.MathSet Set MS = New VBAProject.MathSet Dim 果物 As Variant 果物 = Array("りんご", "みかん", "ばなな") ' "みかん"を除去。 果物 = MS.RemoveElement("みかん", 果物) Debug.Print Join(果物, ";") ' "ぶどう"を追加。 果物 = MS.AddElement("ぶどう", 果物) Debug.Print Join(果物, ";") ' "ばなな"を追加(重複) 果物 = MS.AddElement("ばなな", 果物, True) Debug.Print Join(果物, ";") ' 更に"ばなな"を追加(重複不可) 果物 = MS.AddElement("ばなな", 果物, False) Debug.Print Join(果物, ";") End Sub
結果がこちら。最後の「ばなな追加」は、格納済みの「ばなな」との
重複不可により戻り値が空配列となって、イミディエイトウィンドウ
には何も表示されていない。
次回は「部分集合」の判別に挑戦です。
参考まで。