我正在寻找在Excel VBA中使用的set数据结构。到目前为止我发现的是Scripting.Dictionary,它似乎是map。
在VBA中还有类似的设置吗?
基本上我正在寻找一种有效的数据结构,以确定是否已经添加了特定值。
答案 0 :(得分:4)
看看.NET ArrayList,它有Add
,Contains
,Sort
等方法。您可以在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 :(得分:2)
您可以使用集合并执行以下功能,集合强制使用唯一的密钥标识符:
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
答案 2 :(得分:2)
只需编写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
然后你可以这样使用它:
<强> 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
按预期打印True,False和False。