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 中存储全局使用的列表?
解决方案:
使用 @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
我不知道还能去哪里,我试着找到像我这样的问题,但没有成功。我有一个原始范围 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 中存储全局使用的列表?
解决方案:
使用 @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