Powerpoint VBAを使おう!

Powerpoint VBAやExcelのVBAで遊んでいます。Word VBAも始めました。

Excelデータを扱う コレクションラッパークラス③

chemiphys.hateblo.jp
つつきです。

データ抽出部分を実装してみました。
ここらへんになると,だいぶコードが長くなってくるので良し悪し。

汎用性は失われつつある気はしますが,自分の欲求に特化していく感じです。(;´▽`A``ワタシニハ,ヤクニタツ

標準モジュール

Sub Test()
    Dim Data As DataCollection: Set Data = New DataCollection
    Dim Data2 As DataCollection: Set Data2 = New DataCollection
    Dim TargetSheet As Worksheet: Set TargetSheet = ThisWorkbook.Worksheets(1)
    Data.GetData TargetSheet.Range("a1"), True
    
    Data.Sort 6, False
    
    Data2.SourceCollection = Data.ExtractCollection(1, ">", 1) ', 5 , "=", "データA")
    Data2.LabelData = Data.LabelData
    
    TargetSheet.Range("a11:j18").ClearContents
    Data2.Output ThisWorkbook.Worksheets(1).Range("a11"), True

End Sub

DataCollection.cls
データ抽出用に DataCollectionを別のにコピーできるように内部のCollectionやLabelDataを取得,設定できるように変わりました。
ExtractCollectionという,5キーまで抽出できるFunctionを実装してみています。もうちょい改善が必要。ループで短くもできるのかな。宣言加えればあんまり変わらないかもだけど。
If文のお化けにならなくなったのは,少し成長しました(゚▽゚*)

Option Explicit
Private Col As Collection
Private LabelCol As DataUnit
Private ラベル有 As Boolean
Private ParameterCount As Long

Sub GetData(BaseRange As Range, 先頭行ラベル As Boolean)
    Dim arr: arr = BaseRange.CurrentRegion.value
    Set Col = New Collection
    Set LabelCol = New DataUnit
    Dim i, j
    
    ParameterCount = UBound(arr, 2)
    For i = LBound(arr, 1) To UBound(arr, 1)
        With New DataUnit
            .SetParameterCount ParameterCount
            For j = 1 To ParameterCount
                .LetParameter j, arr(i, j)
            Next
            Col.Add .Self
        End With
    Next
    
    If 先頭行ラベル = True Then
        Set LabelCol = Col(1)
        Col.Remove 1
        ラベル有 = True
    Else
        ラベル有 = False
    End If
    
End Sub

Sub Output(BaseRange As Range, ラベル出力 As Boolean)
    Dim n As Long: n = 1
    Dim d As DataUnit
    Dim i As Long
    If ラベル出力 = True And ラベル有 = True Then
        Col.Add LabelCol, , 1
    End If
    If Col.Count = 0 Then
        BaseRange.value = "該当データなし"
        Exit Sub
    End If
    'GetDataを通っていない場合,コレクションから取得させる
    If ParameterCount = 0 Then ParameterCount = Col(1).パラメーター数
    Dim RangeArray(): ReDim RangeArray(1 To Col.Count, 1 To ParameterCount)
    
    For Each d In Col
        For i = 1 To ParameterCount
            RangeArray(n, i) = d.GetParameter(i)
        Next
        n = n + 1
    Next

    BaseRange.Resize(Col.Count, ParameterCount).value = RangeArray
    
End Sub

Sub Sort(Key As Long, 昇順 As Boolean)
    Dim d1 As Variant, d2 As Variant
    'バブルソート
    Dim i As Long, j As Long
    For i = 1 To Col.Count - 1
        For j = 1 To Col.Count - i
            
            d1 = CallByName(Col(j), "GetParameter", VbMethod, Key)
            d2 = CallByName(Col(j + 1), "GetParameter", VbMethod, Key)
            
            If IsGreater(昇順, d1, d2) Then CollectionSwap Col, j, j + 1
        Next j
    Next i

End Sub

Property Get ExtractCollection(Optional キー1As Variant, Optional 演算子1 As String, Optional1 As Variant, _
                     Optional キー2As Variant, Optional 演算子2 As String, Optional2 As Variant, _
                     Optional キー3As Variant, Optional 演算子3 As String, Optional3 As Variant, _
                     Optional キー4As Variant, Optional 演算子4 As String, Optional4 As Variant, _
                     Optional キー5As Variant, Optional 演算子5 As String, Optional5 As Variant) As Collection
    Dim tCol As Collection: Set tCol = New Collection
    Dim d As DataUnit
    Dim flg追加 As Boolean
    
    For Each d In Col
        flg追加 = True
        If IsMissing(キー1) Then GoTo Flag
        If 抽出演算(d.GetParameter(キー1), 演算子1,1) = False Then flg追加 = False
        If IsMissing(キー2) Then GoTo Flag
        If 抽出演算(d.GetParameter(キー2), 演算子2,2) = False Then flg追加 = False
        If IsMissing(キー3) Then GoTo Flag
        If 抽出演算(d.GetParameter(キー3), 演算子3,3) = False Then flg追加 = False
        If IsMissing(キー4) Then GoTo Flag
        If 抽出演算(d.GetParameter(キー4), 演算子4,4) = False Then flg追加 = False
        If IsMissing(キー5) Then GoTo Flag
        If 抽出演算(d.GetParameter(キー5), 演算子5,5) = False Then flg追加 = False
Flag:
        If flg追加 = True Then tCol.Add d
    Next
    
    Set ExtractCollection = tCol
End Property
Property Get SourceCollection() As Collection
    Set SourceCollection = Col
End Property

Property Let SourceCollection(pCol As Collection)
    Set Col = pCol
End Property

Property Get LabelData() As DataUnit
    Set LabelData = LabelCol
End Property
Property Let LabelData(ラベルデータ As DataUnit)
    If ラベルデータ.パラメーター数 = 0 Then Exit Property
    Set LabelCol = ラベルデータ
    ラベル有 = True
End Property

Private Sub CollectionSwap(pCol As Collection, Index1 As Long, Index2 As Long)
    Dim Item1 As Variant, Item2 As Variant
    Set Item1 = pCol.Item(Index1)
    Set Item2 = pCol.Item(Index2)
    
    pCol.Add Item1, after:=Index2
    pCol.Remove Index2
    pCol.Add Item2, after:=Index1
    pCol.Remove Index1
End Sub

Private Function IsGreater(which, A, B) As Boolean
    Select Case which
        Case True: IsGreater = A > B
        Case False: IsGreater = A < B
    End Select
End Function

Private Function 抽出演算(As Variant, 演算子 As String, 該当値 As Variant) As Boolean
    抽出演算 = False
    Select Case 演算子
        Case "="
            If= 該当値 Then 抽出演算 = True
        Case ">"
            If> 該当値 Then 抽出演算 = True
        Case "<"
            If< 該当値 Then 抽出演算 = True
        Case ">="
            If>= 該当値 Then 抽出演算 = True
        Case "<="
            If<= 該当値 Then 抽出演算 = True
    End Select
End Function

DataUnit.xls
ちょっと余計なパラメーターが増えましたが,最終的には消せるように・・したい。

Option Explicit
Private Parameter()
Private pパラメーター数 As Long

Property Get Self() As Object
    Set Self = Me
End Property

Sub SetParameterCount(パラメーター数 As Long)
    ReDim Parameter(1 To パラメーター数)
    pパラメーター数 = パラメーター数
End Sub

Sub LetParameter(paramNo, value)
    Parameter(paramNo) = value
End Sub

Function GetParameter(paramNo) As Variant
    GetParameter = Parameter(paramNo)
End Function

Property Get パラメーター数() As Long
    パラメーター数 = pパラメーター数
End Property

5キーまで検索を許容するのは,かなりコードが長くなるかなーと思いましたが,以前教えていただいた経験が役に立ったと思っています。
テストは2キーまでしかしていませんけど。。たぶん,いける・・はず。

あとは,目的の列のみ部分抽出,重複除去抽出,該当データ数の出力。

めんどくさそうなとこを先にやりましたし,抽出ができたので,これを利用すれば未実装の部分もいける気がする。