数式の参照元セルが多数存在するワークシートを解析しなければならない場合があります.大抵の場合,一つのセルが他のセルの参照元となっていて,かつ別のセルの参照先になっていることが殆どです.参照元の更に参照元を辿って行くと,それ以上は参照元のない最初のセルに行き着きます.今回の記事ではその最初の参照元のセルを探すコードを紹介します.
2 つの集合が等しいかを確認する方法を用います.ある集合 A と B とが等しいと証明するには,集合 A と集合 B の和と積とをとります.和集合 A ∪ B と積集合 A ∩ B との要素数が等しければ集合 A と集合 B は等しいと言えます.
比較する対象は Range オブジェクトの DirectPrecedents プロパティと Precedents プロパティです.それぞれセルの直接参照元と参照元全てを取得するプロパティであり,それらが一致すれば参照元が最初のセルとなります.前提条件として他のワークシートへの参照がなく,循環参照を使用していないものとします.
セルの参照元と参照先を全て繋ぐと木構造になります.最初の参照元,最後の参照先,どちらのルートから辿っても木構造ができます.構成展開で再帰的にノードを展開し,今回作成した関数でリーフか否かを判定します.フォルダや部品表の展開などで一般的に用いられる手法です.
Option Explicit Sub FirstPrecedents() Dim Sh1 As Worksheet Dim Sh2 As Worksheet Dim i As Long Dim tmp As Range Set Sh1 = ActiveSheet Set Sh2 = Worksheets.Add Sh2.Name = "TraceFormula" i = 1 For Each tmp In Sh1.UsedRange On Error Resume Next If Left(tmp.Formula, 1) = "=" Then If CheckEqualRange(tmp.DirectPrecedents, tmp.Precedents) Then With Sh2 .Cells(i, 1) = tmp.Address .Cells(i, 2) = "'" & tmp.Formula .Cells(i, 3) = tmp.DirectPrecedents.Address .Cells(i, 4) = tmp.Precedents.Address .Cells(i, 5) = tmp.DirectPrecedents.Cells.Count .Cells(i, 6) = tmp.Precedents.Cells.Count .Cells(i, 7) = CheckEqualRange(tmp.DirectPrecedents, tmp.Precedents) End With tmp.DirectPrecedents.Interior.Color = RGB(242, 220, 219) i = i + 1 End If End If On Error GoTo 0 Next tmp End Sub Function CheckEqualRange(ByRef Rng1 As Range, ByRef Rng2 As Range) As Boolean Dim UnionRange As Range Dim IntersectRange As Range Dim tmp As Range CheckEqualRange = False Set UnionRange = Application.Union(Rng1, Rng2) Set IntersectRange = Application.Intersect(Rng1, Rng2) If UnionRange.Cells.Count = IntersectRange.Cells.Count Then CheckEqualRange = True End If End Function
もう一つの方法として,Range オブジェクトの DirectDependents プロパティと DirectPrecedents プロパティを比較する方法もあります.DirectPrecedents プロパティが存在せず,DirectDependents プロパティが存在すればそれはルートであるということです.
Option Explicit Sub FirstPrecedents2() Dim Sh1 As Worksheet Dim Sh2 As Worksheet Dim i As Long Dim tmp As Range Set Sh1 = ActiveSheet Set Sh2 = Worksheets.Add Sh2.Name = "Root" i = 1 For Each tmp In Sh1.UsedRange On Error Resume Next If Left(tmp.Formula, 1) = "=" Then If tmp.DirectPrecedents Is Nothing And _ Not tmp.DirectDependents Is Nothing Then Sh2.Cells(i, 1) = tmp.Address i = i + 1 End If End If On Error GoTo 0 Next tmp End Sub
ついでに参照先の最後のセルを取得するコードも紹介しておきます.条件式の真理値を逆転させるだけです.
Option Explicit Sub LastDependents() Dim Sh1 As Worksheet Dim Sh2 As Worksheet Dim i As Long Dim tmp As Range Set Sh1 = ActiveSheet Set Sh2 = Worksheets.Add Sh2.Name = "Leaf" i = 1 For Each tmp In Sh1.UsedRange On Error Resume Next If Left(tmp.Formula, 1) = "=" Then If tmp.DirectDependents Is Nothing And _ Not tmp.DirectPrecedents Is Nothing Then tmp.Interior.Color = RGB(220, 230, 241) Sh2.Cells(i, 1) = tmp.Address i = i + 1 End If End If On Error GoTo 0 Next tmp End Sub