Excel VBA:需要有关代码体系结构的建议:数据循环和数据提取

Excel VBA: Need advice on code architecture: Data looping and data extraction

提问人:2mas 提问时间:10/17/2023 更新时间:10/19/2023 访问量:74

问:

任务很简单,但我无法将所有部件放在一起。

首先,一些小的数据操作。我有一个包含数据的主表,其中必须将具有相同日期的行合并并提取到另一个工作表上。然后又发生了一些小的数据操作。


'         ReplaceValue = Replace(ReplaceValue, i, "") 'Replace(expression, find, replace, [ start, [ count, [ compare ]]])
'    Next i

Columns("G").replace What:="[0%]", _
                            Replacement:="", _
                            LookAt:=xlPart, _
                            SearchOrder:=xlByRows, _
                            MatchCase:=False, _
                            SearchFormat:=False, _
                            ReplaceFormat:=False

Columns("G").replace What:="[10%]", _
                            Replacement:="", _
                            LookAt:=xlPart, _
                            SearchOrder:=xlByRows, _
                            MatchCase:=False, _
                            SearchFormat:=False, _
                            ReplaceFormat:=False
Columns("G").replace What:="[50%]", _
                            Replacement:="", _
                            LookAt:=xlPart, _
                            SearchOrder:=xlByRows, _
                            MatchCase:=False, _
                            SearchFormat:=False, _
                            ReplaceFormat:=False
Columns("G").replace What:="[200%]", _
                            Replacement:="", _
                            LookAt:=xlPart, _
                            SearchOrder:=xlByRows, _
                            MatchCase:=False, _
                            SearchFormat:=False, _
                            ReplaceFormat:=False

Error2:
End Sub

这是从某个地方偷偷复制的。我的想法:我需要一些东西来遍历行和列。这些列通常固定在第 11 列。底端由许多仅包含“#N/A”的占位符行标记(不要问为什么)。

Sub 2 ()
Dim arr As Variant Dim i As Long, j As Long Dim EndRow as Long

Application.ScreenUpdating = False 'Do I need that?

With Sheets("Mastertable") EndRow = .Range("A:A").Find(what:="#N/A",after:=.Range("A1"), searchdirection:=xlNext).Row End With

'then save the value of EndRow and use it for the next procedure (or function?)

arr = ThisWorkbook.Worksheets("Mastertable").Range(A1:K-EndRow) 'how to enter this correctly? 'K := 11th column, EndRow := last row just found

For i = LBound(arr, 1) To UBound(arr, 1) For j = LBound(arr, 2) To UBound(arr, 2)

'Here stuff has to happen

Next j

Next i

'Extraction of data 

ThisWorkbook.Worksheets("Mastertable").Range("Mastertable").Value = arr

End Sub

你怎么能说“根据日期从我的数组中分组我的东西”,将相似的日期导出到按时间顺序放置在其他新工作表旁边的新工作表,用相应的日期命名它们。我不知道如何完成这项任务,也许你可以在这里指导我

有一列写满了公司名称。每个日期生成的工作表一次仅包含一家公司(不同公司的日期不同)。因此,如果有值,则必须检查该列,然后整个列都应填充该文本。

Sub 3 ()

'no idea

在我看来,这一步应该集成到带有数组的部分中,否则我必须遍历所有新工作表,然后再次在工作表中循环......同样需要指导

数组 Excel VBA 体系结构

评论

0赞 CDP1802 10/17/2023
为什么整个栏目都要填满这段文字。 如果有一列充满了公司名称?哪些列是“日期”和“公司”?
0赞 VBasic2008 10/17/2023
如果您没有其他适合该模式的百分比,并且想要保留它们,则可以替换第一个代码片段。其余的,几乎没有足够的信息。努力。您需要准确解释需要复制的内容和位置。添加源工作表和目标工作表之一的屏幕截图将澄清很多内容。Columns("G").Replace What:="[*%]", Replacement:="", LookAt:=xlPart
0赞 taller 10/17/2023
请在 OP 中共享数据布局和示例数据。
0赞 2mas 10/18/2023
我无法对数据进行匿名化处理,这太清楚了,我在做什么以及我在哪里工作。也许我的能力也不够,请耐心等待。我有一个用作数据库的主表。数据库中的一行称为任务,其中包含完成此特殊任务(建筑、项目管理)的所有内容、注释、名称等。基本上,我按日期对所有这些东西进行排序。每个日期都由某个公司必须执行的几个任务行组成。对我来说,挑战是生成以日期为名称的工作表。分配给这一天的每项任务都只由一家公司完成。
0赞 2mas 10/18/2023
数据库不完整,这就是为什么在将按日期排序的任务复制到单个工作表中后,我想简单地将一个任务的公司名称复制到另一个任务中,因为一天只有一个公司名称!这是“完成”数据库的一种方式;请不要要求任何其他程序,我被指示完全以这种方式进行,并且无法更改过程的逻辑

答:

1赞 VBasic2008 10/18/2023 #1

添加与列值(日期)对应的工作表

enter image description here

Sub ExtractCompanyData()
    
    ' Define constants.
    
    Const SRC_SHEET_NAME As String = "MasterTable"
    Const DATA_COLUMNS As String = "A:K"
    Const DATE_COLUMN As Long = 2
    Const COMPANY_COLUMN As Long = 3
    Const DST_FIRST_CELL As String = "A1"
    Const DST_DATE_FORMAT As String = "mm\/dd\/yyyy"
    Const DST_SHEET_NAME_DATE_FORMAT As String = "mm-dd-yyyy"
    Const COPY_HEADERS As Boolean = True
 
    Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
    
    ' Return the source data in an array ('sData').
    
    Dim sws As Worksheet: Set sws = wb.Sheets(SRC_SHEET_NAME)
    Dim srg As Range: Set srg = sws.UsedRange.Columns(DATA_COLUMNS)
    Dim srCount As Long: srCount = srg.Rows.Count
    Dim cCount As Long: cCount = srg.Columns.Count
    Dim sData() As Variant: sData = srg.Value
    
    ' An Incomplete Description of the Dictionary and the Collection
    ' A dictionary consists of two arrays: one is called 'Keys' and the other
    ' is called 'Items' ('Values'). Each key has an associated item
    ' and they form a so-called 'key-value pair'.
    ' Each key needs to be unique while its item can hold various data types,
    ' in this case, a collection ('object').
    ' A collection is similar but simpler.
    ' Each of a collection's 'item' needs to be unique.
    ' The collection is used because it is more efficient and you can simply
    ' add just an item to it while you need to add a value pair to a dictionary.
    
    ' Return the unique dates ('sDate') from the source array ('sData')
    ' in the 'keys' of a dictionary.
    ' Each key's corresponding 'item' will hold a collection whose 'items'
    ' will hold the rows ('sr') where each date ('sDate', key) was found.
    
    Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
    
    Dim sDate As Variant, sr As Long
    
    For sr = 2 To srCount ' skip headers
        sDate = sData(sr, DATE_COLUMN)
        If IsDate(sDate) Then
            If Not dict.Exists(sDate) Then
                ' Create the 'sDate' key in the dictionary
                ' and add a new collection to the key's associated item.
                dict.Add sDate, New Collection
                ' or:
                'Set dict(sDate) = New Collection
            End If
            dict(sDate).Add sr ' add the row to the items of the collection
        End If
    Next sr

    ' Loop through the keys (dates) of the dictionary, and by applying
    ' the required logic, copy the data to the destination worksheet.

    Application.ScreenUpdating = False

    Dim dws As Worksheet, drg As Range, ddrg As Range
    Dim dData() As Variant, sRow As Variant
    Dim dr As Long, idr As Long, drCount As Long, c As Long
    Dim dwsName As String, Company As String, IsCompanyFound As Boolean
    
    ' Loop through the keys (dates) of the dictionary.
    For Each sDate In dict.Keys
        
        ' Define the destination array.
        drCount = dict(sDate).Count - COPY_HEADERS
        ReDim dData(1 To drCount, 1 To cCount)
        
        ' Write the headers to the destination array.
        ' Also, determine the used destination array rows ('idr', 'dr')
        ' i.e. the inital row, the first row to be written to minus one.
        If COPY_HEADERS Then
            For c = 1 To cCount
                dData(1, c) = sData(1, c)
            Next c
            idr = 1
        Else
            idr = 0
        End If
        dr = idr
        
        ' Loop through the items ('sRow') of the collection ('dict(sDate)'),
        ' held by the current key's ('dDate') corresponding item ('dict(sDate)'),
        ' and write the values from each corresponding row ('sRow')
        ' of the source array ('sData') to the next row ('dr')
        ' of destination array ('dData') skipping the company column.
        ' Also, attempt to determine the company name.
        For Each sRow In dict(sDate)
            dr = dr + 1
            For c = 1 To cCount
                If c <> COMPANY_COLUMN Then
                    dData(dr, c) = sData(sRow, c)
                End If
            Next c
            If Not IsCompanyFound Then
                Company = CStr(sData(sRow, COMPANY_COLUMN))
                If Len(Company) > 0 Then IsCompanyFound = True
            End If
        Next sRow
        
        ' Loop through the rows ('dr') of the destination array ('dData')
        ' and write the company name ('Company') to the company column.
        If IsCompanyFound Then
            For dr = idr + 1 To drCount
                dData(dr, COMPANY_COLUMN) = Company
            Next dr
            IsCompanyFound = False ' reset for the next iteration
        End If
        
        ' Determine the destination worksheet name ('dwsName').
        dwsName = Format(sDate, DST_SHEET_NAME_DATE_FORMAT)
        
        ' Delete an existing same named sheet.
        Application.DisplayAlerts = False
            On Error Resume Next
                wb.Sheets(dwsName).Delete
            On Error GoTo 0
        Application.DisplayAlerts = True
        
        ' Add a new worksheet ('dws') and rename it accordingly.
        Set dws = wb.Sheets.Add(After:=wb.Sheets(wb.Sheets.Count))
        dws.Name = dwsName
        
        ' Copy the values from the destination array ('dData')
        ' to the destination range ('drg').
        Set drg = dws.Range(DST_FIRST_CELL).Resize(drCount, cCount)
        drg.Value = dData
        
        ' Apply formatting to the destination (range, worksheet).
        With drg
            ' Format headers and reference the destination data range ('ddrg').
            If COPY_HEADERS Then
                With .Rows(1)
                    .Font.Bold = True
                End With
                Set ddrg = drg.Resize(drCount - 1).Offset(1)
            Else
                Set ddrg = drg
            End If
            ' Format the destination data range ('ddrg').
            With ddrg
                ' Format the destination date column.
                With ddrg.Columns(DATE_COLUMN)
                    .NumberFormat = DST_DATE_FORMAT
                End With
            End With
            ' Format the entire destination columns.
            .EntireColumn.AutoFit
        End With
        
    Next sDate
    
    ' Additional Ideas
    
    'sws.Activate
    'wb.Save

    Application.ScreenUpdating = True
    
    ' Inform.
    
    MsgBox "Company data extracted.", vbInformation
    
End Sub

填充词典的视觉呈现

enter image description here

评论

0赞 2mas 10/19/2023
它有效!但我几乎什么也没学到。我有没有可能联系你,这样我们就可以通过代码了吗?我有很多问题
0赞 VBasic2008 10/19/2023
我更正并扩展了一些评论。欢迎在此评论部分提出几个问题。如果您有很多,我的个人资料页面上有一个电子邮件地址。发一封电子邮件,如果不是太苛刻,我会回复。这个网站通常用于提出一个问题(远不如您的要求),并有一两个密切相关的后续问题。
0赞 2mas 10/25/2023
这里发生了什么:“dData(dr, c)”?dData 是对象,dr 和 c 是 ...?如果我不想搜索公司名称,我需要省略什么?
0赞 2mas 10/25/2023
For Each sRow In dict(sDate) dr = dr + 1 For c = 1 To cCount dData(dr, c) = sData(sRow, c) Next c Next sRow应该只有这块吧?
0赞 VBasic2008 10/25/2023
完全。你一直很忙。你应该删除整个块。我想。If IsCompanyFound... End If