【问题标题】:VBA values of collection into Excel using VBA使用 VBA 将 VBA 值收集到 Excel 中
【发布时间】:2015-08-22 22:16:12
【问题描述】:

我正在尝试使用 VBA 代码将值复制到 Excel 工作表中。我一直在尝试使用字典(如在我的函数 (8) 中使用并在第 (3) 和 (4) 节中使用)。当我将它设置为字典时,一切都被关闭了,所以我将字典更改为集合。现在问题出在d.Resize(dict.count, 1).Value = Application.Transpose(dict.count) 行(在第3 节和第4 节),因为它正在计算值并输出值的数量而不是值的名称。

我认为我需要将其更改为更像 d.Resize(dict.count, 1).Value = Application.Transpose(VariantArray) 的内容,但我不知道如何定义键和值,因为我不是在打印特定范围,而是在特定标题下显示任何内容。

这是一个很难用语言表达的想法,所以如果我解释得不够清楚,请随时要求我解释得更好,我会尝试更多地引导你。

这是我的代码,非常感谢任何帮助!

Option Explicit

Sub LoopThroughDirectory()

    Const ROW_HEADER As Long = 10

    Dim objFSO As Object
    Dim objFolder As Object
    Dim objFile As Object
    Dim MyFolder As String
    Dim StartSht As Worksheet, ws As Worksheet
    Dim WB As Workbook
    Dim i As Integer
    Dim LastRow As Integer, erow As Integer
    Dim Height As Integer
    Dim RowLast As Long
    Dim f As String
    Dim dict As Object
    Dim hc As Range, hc1 As Range, hc2 As Range, hc3 As Range, d As Range

    Set StartSht = Workbooks("masterfile.xlsm").Sheets("Sheet1")

    'turn screen updating off - makes program faster
    Application.ScreenUpdating = False
    'Application.UpdateLinks = False

    'location of the folder in which the desired TDS files are
    MyFolder = "C:\Users\trembos\Documents\TDS\progress\"

    'find the headers on the sheet
    Set hc1 = HeaderCell(StartSht.Range("B1"), "HOLDER")
    Set hc2 = HeaderCell(StartSht.Range("C1"), "CUTTING TOOL")

    'create an instance of the FileSystemObject
    Set objFSO = CreateObject("Scripting.FileSystemObject")
    'get the folder object
    Set objFolder = objFSO.GetFolder(MyFolder)
    i = 2




    'loop through directory file and print names
'(1)
    For Each objFile In objFolder.Files
        If LCase(Right(objFile.Name, 3)) = "xls" Or LCase(Left(Right(objFile.Name, 4), 3)) = "xls" Then
'(2)
            'print file name to Column 1

            'Open folder and file name, do not update links
            Set WB = Workbooks.Open(fileName:=MyFolder & objFile.Name, UpdateLinks:=0)
            Set ws = WB.ActiveSheet


'(3)
                'find CUTTING TOOL on the source sheet
                Set hc = HeaderCell(ws.Cells(ROW_HEADER, 1), "CUTTING TOOL")
                If Not hc Is Nothing Then

                    Set dict = GetNames(hc.Offset(1, 0))
                    If dict.count > 0 Then
                        Set d = StartSht.Cells(Rows.count, hc2.Column).End(xlUp).Offset(1, 0)
                        'add the values to the masterfile, column 3
                        d.Resize(dict.count, 1).Value = Application.Transpose(dict.count)
                    End If
                Else
                    'header not found on source worksheet
                End If

'(4)
                'find HOLDER on the source sheet
                Set hc3 = HeaderCell(ws.Cells(ROW_HEADER, 1), "HOLDER")
                If Not hc3 Is Nothing Then

                    Set dict = GetNames(hc3.Offset(1, 0))
                    If dict.count > 0 Then
                        Set d = StartSht.Cells(Rows.count, hc1.Column).End(xlUp).Offset(1, 0)
                        'add the values to the master list, column 2
                        d.Resize(dict.count, 1).Value = Application.Transpose(dict.count)
                    End If
                Else
                    'header not found on source worksheet
                End If

'(5)
            With WB
               'print TDS information
                For Each ws In .Worksheets
                        'print the file name to Column 1
                        StartSht.Cells(i, 1) = objFile.Name
                        'print TDS name from J1 cell to Column 4
                        With ws
                            .Range("J1").Copy StartSht.Cells(i, 4)
                        End With
                        i = GetLastRowInSheet(StartSht) + 1
                'move to next file
                Next ws
'(6)
                'close, do not save any changes to the opened files
                .Close SaveChanges:=False
            End With
        End If
    'move to next file
    Next objFile
    'turn screen updating back on
    Application.ScreenUpdating = True
    ActiveWindow.ScrollRow = 1
'(7)
End Sub

'(8)
'get all unique column values starting at cell c
Function GetNames(ch As Range) As Object
    Dim dict As Object, rng As Range, c As Range, v
    Set dict = New Collection
    For Each c In ch.Parent.Range(ch, ch.Parent.Cells(Rows.count, ch.Column).End(xlUp)).Cells
        v = Trim(c.Value)
        If Len(v) > 0 Then
            dict.Add v
        End If
    Next c
    Set GetNames = dict
End Function

'(9)
'find a header on a row: returns Nothing if not found
Function HeaderCell(rng As Range, sHeader As String) As Range
    Dim rv As Range, c As Range
    For Each c In rng.Parent.Range(rng, rng.Parent.Cells(rng.Row, Columns.count).End(xlToLeft)).Cells
        If Trim(c.Value) = sHeader Then
            Set rv = c
            Exit For
        End If
    Next c
    Set HeaderCell = rv
End Function

'(10)
Function GetLastRowInColumn(theWorksheet As Worksheet, col As String)
    With theWorksheet
        GetLastRowInColumn = .Range(col & .Rows.count).End(xlUp).Row
    End With
End Function

'(11)
Function GetLastRowInSheet(theWorksheet As Worksheet)
Dim ret
    With theWorksheet
        If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
            ret = .Cells.Find(What:="*", _
                          After:=.Range("A1"), _
                          Lookat:=xlPart, _
                          LookIn:=xlFormulas, _
                          SearchOrder:=xlByRows, _
                          SearchDirection:=xlPrevious, _
                          MatchCase:=False).Row
        Else
            ret = 1
        End If
    End With
    GetLastRowInSheet = ret
End Function

【问题讨论】:

  • Dictionary 不同,您不能一次性将Collection 中的所有项目返回到数组中。原始代码是什么,它的确切问题是什么?
  • 哦,我明白了,@Rory。我的原始代码运行良好,但我需要它包含重复项,并且它设置为仅采用 UniqueValue(不包括重复项的值)。你知道我该如何解决这个问题吗?这是我的完整原始代码。 pastie.org/10229387
  • 如果您需要允许重复,请将值用作项,而不是键。
  • @Rory,好的,我理解其中的逻辑,但您认为您可以进一步解释吗?我当然不是 VBA 方面的专家,所以如果可以的话,一个示例或特定的代码行会很有帮助

标签: vba excel dictionary collections


【解决方案1】:

由于您想要所有值,而不仅仅是唯一列表,请将 Dictionary 代码更改为:

Function GetValues(ch As Range) As Object
    Dim dict As Object, rng As Range, c As Range, v
    Set dict = CreateObject("scripting.dictionary")
    For Each c In ch.Parent.Range(ch, ch.Parent.Cells(Rows.Count, ch.Column).End(xlUp)).Cells
        v = Trim(c.Value)
        If Len(v) > 0 And Not dict.exists(v) Then
            dict.Add c.Address, v
        End If
    Next c
    Set GetValues = dict
End Function

然后使用Items 数组,而不是Keys 数组:

                Set dict = GetValues(hc3.Offset(1, 0))
                If dict.Count > 0 Then
                    Set d = StartSht.Cells(Rows.Count, hc1.Column).End(xlUp).Offset(1, 0)
                    'add the values to the master list, column 2
                    d.Resize(dict.Count, 1).Value = Application.Transpose(dict.items)
                End If

【讨论】:

  • 你太棒了。我现在绝对明白了!非常感谢您花时间向我解释。我真的很感激!
【解决方案2】:

要使用 Collection 对象获取唯一项目,您需要一个 key。例如:

这将获得唯一性:

Sub MAIN()
   Dim z As Collection, r As Range
   Set r = Range("A1:A4")

   Set z = GetNames(r)

   msg = z.Count & vbCrLf
   For i = 1 To z.Count
      msg = msg & z.Item(i) & vbCrLf
   Next i
   MsgBox msg
End Sub

'get all unique column values starting at cell c
Function GetNames(ch As Range) As Collection
    Dim dict As Collection, rng As Range, c As Range, v
    Set dict = New Collection
    For Each c In ch.Parent.Range(ch, ch.Parent.Cells(Rows.Count, ch.Column).End(xlUp)).Cells
        v = Trim(c.Value)
        If Len(v) > 0 Then
         On Error Resume Next
            dict.Add v, CStr(v)
         On Error GoTo 0
        End If
    Next c
    Set GetNames = dict
End Function

【讨论】:

  • 好的。因此,您的代码中的 r 被分配到特定范围的单元格,然后 z 利用 r 在 Sub 部分中获取这些单元格的名称。如果我不使用容易定义的范围,你知道我将如何在给定我的代码的情况下设置类似于“r”的东西吗? @Gary 的学生
  • @Taylor 我的代码应该与您的代码插件兼容......以同样的方式使用它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-26
  • 1970-01-01
  • 1970-01-01
  • 2021-06-14
  • 1970-01-01
相关资源
最近更新 更多