2017-01-18 12 views
3

Excel VBAで使用するsetデータ構造を探しています。私が今までに見つけたのは、mapと思われるScripting.Dictionaryです。VBAでデータ構造を設定

VBAにも同様の設定がありますか?

基本的には、特定の値が既に追加されているかどうかを調べるのに有効なデータ構造を探しています。

+1

多分、あなたはおそらく配列 – Storax

+0

のコレクションを意味するでしょうか?コレクションですか?それともクラス? – Pierre

+0

重複を見つけようとしています。限り、私は配列とコレクションまたはインデックスされていないことを理解しているので、特定の値が存在しているかどうかを見つけるためにすべてを横断しなければならないだろう。 – Sandro

答えて

1

あなたは、コレクションを使用して、次の機能を行うことができ、コレクションが一意のキー識別子を強制:

Public Function InCollection(Col As Collection, key As String) As Boolean 
    Dim var As Variant 
    Dim errNumber As Long 

    InCollection = False 
    Set var = Nothing 

    Err.clear 
    On Error Resume Next 
    var = Col.Item(key) 
    errNumber = CLng(Err.Number) 
    On Error GoTo 0 

    '5 is not in, 0 and 438 represent incollection 
    If errNumber = 5 Then ' it is 5 if not in collection 
    InCollection = False 
    Else 
    InCollection = True 
    End If 

End Function 
+0

詳細な回答ありがとうございます! 'Scripting.Dictionary'を使うこととの違いは何ですか?ディクショナリを使用する方が、「存在する」という方法があるので、直感的に思えます。コレクションと辞書の両方がキー値構造であるように見えるので、私は別のデータ構造を探していました。キーが必要です。 – Sandro

+1

これは、コレクション対辞書に関する優れた情報源です(https://www.experts-exchange.com/articles/3391/Using-the-Dictionary-Class-in-VBA.html)。実際には両方ともこの目的のためにうまくいくので、どちらがより快適であるかを選んでください。 – Zerk

3

.NET ArrayListを見てみましょう、それはAddContainsSortなどのような方法を持っているあなたは、インスタンス化することができますVBSやVBA環境内のオブジェクト:

Set ArrayList = CreateObject("System.Collections.ArrayList") 

Scripting.Dictionaryもニーズに合わせて、それが一意キーを持っている、Exists方法すべてキーがすでに辞書に入っているかどうかを確認します。

しかし、ADODB経由のSQLリクエストは、おそらくこのケースではより効率的です。以下の例は、ワークシートにSQLクエリを経由してユニークな行を取得する方法を示しています。

Option Explicit 

Sub GetDistinctRecords() 

    Dim strConnection As String 
    Dim strQuery As String 
    Dim objConnection As Object 
    Dim objRecordSet As Object 

    Select Case LCase(Mid(ThisWorkbook.Name, InStrRev(ThisWorkbook.Name, "."))) 
     Case ".xls" 
      strConnection = "Provider=Microsoft.Jet.OLEDB.4.0;User ID=Admin;Data Source='" & ThisWorkbook.FullName & "';Mode=Read;Extended Properties=""Excel 8.0;HDR=YES;"";" 
     Case ".xlsm", ".xlsb" 
      strConnection = "Provider=Microsoft.ACE.OLEDB.12.0;User ID=Admin;Data Source='" & ThisWorkbook.FullName & "';Mode=Read;Extended Properties=""Excel 12.0 Macro;HDR=YES;"";" 
    End Select 

    strQuery = "SELECT DISTINCT * FROM [Sheet1$]" 
    Set objConnection = CreateObject("ADODB.Connection") 
    objConnection.Open strConnection 
    Set objRecordSet = objConnection.Execute(strQuery) 
    RecordSetToWorksheet Sheets(2), objRecordSet 
    objConnection.Close 

End Sub 

Sub RecordSetToWorksheet(objSheet As Worksheet, objRecordSet As Object) 

    Dim i As Long 

    With objSheet 
     .Cells.Delete 
     For i = 1 To objRecordSet.Fields.Count 
      .Cells(1, i).Value = objRecordSet.Fields(i - 1).Name 
     Next 
     .Cells(2, 1).CopyFromRecordset objRecordSet 
     .Cells.Columns.AutoFit 
    End With 

End Sub 

ソース・データがSheet1に配置する必要があり、その結果はSheet2に出力されます。その方法の唯一の制限は、ADODBがドライブのExcelブックに接続するため、実際の結果を得るためにクエリの前に変更を保存する必要があることです。

あなたは非明確な行のセットのみを取得したい場合は、次のようにクエリをする必要があります(あくまで一例、クエリにフィールドのあなたのセットを配置する必要があります):

strQuery = "SELECT CustomerID, CustomerName, ContactName, Address, City, PostalCode, Country FROM [Sheet1$] GROUP BY CustomerID, CustomerName, ContactName, Address, City, PostalCode, Country HAVING Count(*) > 1" 
+1

うわー、私はExcel内でSQLクエリを実行することが可能であるかどうかはわかりませんでした。私の使用事例では、検証のために使用するので、保存せずに動作するはずです。これは何とかこの方法で可能ですか?私は、私はセットのデータ構造を求めているので、私はこの答えを受け入れることができないと思う。これが受け入れられた答えであれば、データ構造を探している人にとってはミスリーディングになるでしょう。 – Sandro

+0

@Sandroどのような種類の検証が必要かを明確にしてください。有効な行と無効な行はどのように表示されるべきですか? – omegastripes

+0

あなたの答えは、まず保存する必要があることを除いて、私がやろうとしていたことをするようです。これまでのところ、行の表示方法はまだ決まっていません。これまではScripting.Dictionaryを使用していましたが、これはSetではありませんが、処理が完了しました。 – Sandro

1

単にセット様の操作だけを公開するScripting.Dictionaryのラッパーを記述します。

clsSet

Option Explicit 

Private d As Scripting.Dictionary 

Private Sub Class_Initialize() 
    Set d = New Scripting.Dictionary 
End Sub 

Public Sub Add(var As Variant) 
    d.Add var, 0 
End Sub 

Public Function Exists(var As Variant) As Boolean 
    Exists = d.Exists(var) 
End Function 

Public Sub Remove(var As Variant) 
    d.Remove var 
End Sub 

そして、あなたはそうのようにそれを使用することができます:予想通り、真偽とFalse出力し

mdlMain

Public Sub Main() 
    Dim s As clsSet 
    Set s = New clsSet 

    Dim obj As Object 

    s.Add "A" 
    s.Add 3 
    s.Add #1/19/2017# 

    Debug.Print s.Exists("A") 
    Debug.Print s.Exists("B") 
    s.Remove #1/19/2017# 
    Debug.Print s.Exists(#1/19/2017#) 
End Sub