VBA Excel - 在 VBA 中存储列表的方法?

VBA Excel - ways to store lists in VBA?

我不知道还能去哪里,我试着找到像我这样的问题,但没有成功。我有一个原始范围 table,我想将信息复制到一个新的 sheet,然后将复制的信息转换成一个 ListObject table。我已经解决了 99%,但后来我想将复制的 table 的原始 headers 更改为我自己的 headers(因为大多数原始 header非常冗长)。

我构建了一个循环来查看 [#Headers] 单元格,找到与某个原始值匹配的值,然后用我自己的值替换它。例如

For Each cl In Range("Table1[#Headers]")
        If cl.Value = "Employee" Then
            cl.Value = "Name"
        ElseIf cl = "Employer Name" Then
            cl.Value = "Company"
'...
        End If
Next cl

有一段代码为 30 多个实例执行此操作很麻烦,如果我收到的原始信息以某种方式改变了它的 header 值,那么我必须再次寻找这段代码并制作变化。我希望有一种方法可以存储任何 Sub 都可以引用的 before-and-after header 名称的 2 列列表,例如全局数组(除了全局数组是不可能的)。我调查了 类,但我在全球化信息方面又遇到了问题。

我正在考虑制作一个包含 2 列列表的隐藏作品sheet,但我真的希望这不是必需的,我不想要比我更多的 sheet具有。有没有办法在 Excel VBA 中存储全局使用的列表?

Example image

解决方案:

使用 @Mat's Mug 建议,我将展示我是如何弄清楚如何添加我的词典的。

我制作了一个名为 DHeader 的 public 变体,并创建了一个 Sub to Call from:

Public DHeader As Dictionary

Sub Load_Headers()

If Not DHeader Is Nothing Then Exit Sub
Set DHeader = New Dictionary

With DHeader
    .add "Employee", "Name"
    .add "Employer Name", "Company"
    '...
End With

End Sub

然后在我的 Action Sub 中添加了这个:

Call Load_Headers
For Each i_1 In Range("Table1[#Headers]")
    If DHeader.Exists(CStr(i_1.Value)) = True Then
        i_1.Value = DHeader.Item(CStr(i_1.Value))
    End If
Next i_1

现在我的价值观和行动被分成了我的代码的不同部分。我想我仍然必须添加一种方法来清除我的操作子中的字典,但它有效!

无论您做什么,都需要映射代码在某处

如果巨大的 If-Then-Else 块不是很吸引人,您可以考虑使用 Dictionary object,来自 Scripting 库 - 使用 "before" 列名作为字典键,"after" 列名作为字典值,映射代码可能如下所示:

Dim ColumnMap As New Scripting.Dictionary
With ColumnMap
    .Add "Employee", "Name"
    .Add "Employer Name", "Company"
    '...
End With

然后当您迭代 header 行中的单元格时,您可以验证字典中是否存在 name/key,然后通过获取映射值继续重命名。只是不要 假设 列名存在于字典中,否则你会 最终 运行 变成 "Key does not exist" 运行时间错误。

字典的替代方法(虽然这可能是我的首选方法,但我会在单独的过程中初始化它们)是拆分字符串:

Sub DoStuff()
Const RawList As String = "Employee,Employer Name"
Const UpdateList as String = "Name,Employer"
Dim rawHeaders as Variant
Dim headers as Variant

rawHeaders = Split(RawList, ",")
headers = Split(UpdateList, ",")

    For Each cl In Range("Table1[#Headers]")
        If Not IsError(Application.Match(cl.Value, rawHeaders, False)) Then
            cl.Value = headers(Application.Match(cl.Value, rawHeaders, False))
        End If
    Next

End Sub

您可以改为在模块级别限定数组的范围,以便它们可用于其他过程调用等。

为什么不使用简单的 VBA Collection?不需要额外的引用,不需要后期绑定,它直接构建到 VBA.

注意:如果在地图中找不到该项目,则原始原始 header 值不会被替换,只是被跳过。

Option Explicit

Public Sub Main()
    Dim header As Range

    Set header = Worksheets("RawData").ListObjects("Table1").HeaderRowRange

    ReplaceInheaderRow headerRow:=header

    ' header contains transformed values now
End Sub

Private Function ReplaceInheaderRow(ByVal headerRow As Range) As Range
    Dim map As Collection
    Set map = New Collection

    map.Add "Name", "Employee"
    map.Add "Company", "Employer Name"
    map.Add "ID", "ID Numbers"
    map.Add "Income", "Wages"
    map.Add "etc.", "Some next column name"

    On Error Resume Next

    Dim rowHeaderCell As Range

    For Each rowHeaderCell In headerRow
        rowHeaderCell.Value = map(rowHeaderCell.Value)
    Next rowHeaderCell

    On Error GoTo 0
End Function