【问题标题】:Is there a way to loop through a range of cells and assign each value in the cell to different variables?有没有办法遍历一系列单元格并将单元格中的每个值分配给不同的变量?
【发布时间】:2021-03-06 17:01:49
【问题描述】:

我有一个 Range ("A1:A"+finalRow),其中 finalRow 是 "A" 列的最后一行,他的值随机变化。

我需要从范围中提取每个值并将每个值分配给不同的变量名,例如var1, var2, ..., var+finalRow。

在这种情况下,我有 20 个单元格/值,我的部分代码如下:

For y = 1 To finalRow
    
    If finalRow = 20 Then
        res1 = Range("A" + y).Value
        pos1 = Range(1, y + 4).Address
        res2 = Range("A" + y).Value
        pos2 = Range(1, y + 4).Address
        res3 = Range("A" + y).Value
        pos3 = Range(1, y + 4).Address
        '...
        res20 = Range("A" + y).Value
        pos20 = Range(1, y + 4).Address
        
    ElseIf finalRow = 19 Then
        res1 = Range("A" + y).Value
        pos1 = Range(1, y + 4).Address
        res2 = Range("A" + y).Value
        pos2 = Range(1, y + 4).Address
        res3 = Range("A" + y).Value
        pos3 = Range(1, y + 4).Address
        '...
        res19 = Range("A" + y).Value
        pos19 = Range(1, y + 4).Address
        
    ElseIf finalRow = 18 Then
        '...
    
    ElseIf finalRow = 1 Then
        res1 = Range("A" + y).Value
        pos1 = Range(1, y + 4).Address
    
Next y

是否可以在不创建大量代码的情况下进行范围游览?

【问题讨论】:

  • 使用数组...这么多变量是代码的味道。
  • 看看arrays
  • 尝试使用字典。单元格地址将是项目的键和单元格值。
  • 您可以将一系列单元格中的值/地址分配给变量数组(例如,将 myValues 作为 Variant,将 myAddresses 作为 Variant,然后 myValues = .Range("A1:A" +finalrow).value 等。因为您使用的是两个数组,所以您需要使用 LBound 和 UBound 遍历这些数组。
  • 你能解释一下“我需要什么”的意思吗?您可能会收到一些代码来覆盖它。否则,我认为不熟悉数组或字典会更难理解我们的建议。

标签: excel vba


【解决方案1】:

变量之山

守则

Option Explicit

Sub AMoutainOfVariables()

    Const FirstRow As Long = 1
    Const ColumnString As String = "A"
    Const ColumnOffset As Long = 4
    
    Dim wb As Workbook
    Set wb = ThisWorkbook ' The workbook containing this code.
    
    Dim ws As Worksheet
    Set ws = wb.ActiveSheet ' Better qualify with e.g. wb.worksheets("Sheet1").
    
    Dim FinalRow As Long
    FinalRow = 20
    
    ' Get values and cell addresses into an array.
    Dim Data As Variant
    Data = getColumnVnA(ws, ColumnString, FirstRow, FinalRow, , ColumnOffset)
    
    ' Now instead of
    '    res1, pos1, res2, pos2 ... you use:
    '    Data(1, 1), Data(1, 2), Data(2, 1), Data(2, 2) ...
    
    ' Now you can do something like the following.
    
    ' Write values and cell addresses to the Immediate window (CTRL+G).
    Dim i As Long
    For i = 1 To UBound(Data, 1)
        Debug.Print Data(i, 1), Data(i, 2)
    Next i

End Sub
    
' Writes the values and cell addresses of a one-column range, defined by its
' column string and first and last row numbers, to a 2D one-based two-column
' array.
Function getColumnVnA(Sheet As Worksheet, _
                      Optional ByVal ColumnString As String = "A", _
                      Optional ByVal FirstRowNumber As Long = 1, _
                      Optional ByVal LastRowNumber As Long = 1, _
                      Optional ByVal RowOffset As Long = 0, _
                      Optional ByVal ColumnOffset As Long = 0) _
         As Variant
    ' Calculate Number of Rows ('NoR').
    Dim NoR As Long
    NoR = LastRowNumber - FirstRowNumber + 1
    ' Write values from One-Column Range to Data Array ('Data').
    Dim Data As Variant
    If NoR > 1 Then
    ' One-Column Range contains multiple cells.
        Data = Sheet.Cells(FirstRowNumber, ColumnString).Resize(NoR).Value
    Else
    ' One-Column Range contains one cell only.
        ReDim Data(1 To 1, 1 To 1)
        Data = Sheet.Cells(FirstRowNumber, ColumnString).Value
    End If
    ' 'Add' a column to Data Array.
    ReDim Preserve Data(1 To NoR, 1 To 2)
    ' Write cell addresses to 2nd column of Data Array.
    Dim i As Long
    For i = 1 To NoR
        Data(i, 2) = Sheet.Range(ColumnString & CStr(i + FirstRowNumber - 1)) _
                          .Offset(RowOffset, ColumnOffset).Address(0, 0)
    Next i
    ' Write result.
    getColumnVnA = Data
End Function

【讨论】:

    【解决方案2】:

    使用数组来简化你的代码,你可以这样做(当然解释性的 cmets 可以省略!!):

    Dim Res(1 To 20) As Variant '-- Amended per VBasic2008's helpful suggestion
    Dim Pos(1 To 20) As Variant
    Dim y As Long
    
    '-- NOTE: It's good practice to explicitly reference your workbook and worksheet.
    '-- If you specify just "Range" without qualification, it will refer to whichever
    '-- worksheet is active, and if you have more than one Excel workbook open,
    '-- you could get unexpected results if you switch between workbooks. 
    '-- "ThisWorkbook" ensures you are referring to the workbook that's running this code.
    '-- Sheets("Sheet1") ensures you are dealing with the named sheet only. Now ".Range" 
    '-- (don't omit the "."!!) can only refer to the cells in ThisWorkbook on Sheet1.
    
    With ThisWorkbook.Sheets("Sheet1")
        For y = 1 To finalRow
            Res(y) = .Range("A" & y).Value
            Pos(y) = .Cells(1, y + 4).Address
        Next
    End With
    

    现在,无论您当前使用 Res1、Res2 等,您都将引用 Res(1)、Res(2)...(即数组元素)。

    还有两点:
    您需要在 Range 引用中使用“&”而不是“+”。
    您的 .Range(1, y + 4) 将不起作用。假设您在这里尝试使用 Row/Col 组合,它需要是 .Cells(1, y + 4)。

    【讨论】:

    • 您已经将数组定义为 22 (0-21) 个元素,并且您没有使用第一个 (0) 和最后一个 (21),但您可以定义它们,例如像这样:Dim Res(1 To 20) As Variant。此外,应在设置 finalRow 之后定义数组,例如Dim Res(1 To finalRow) As Variant.
    • @VBasic2008 两者都好。我会修改答案。
    • @VBasic2008 关于finalRow,好像是在别处定义的,所以我把这段代码段中的定义去掉了。感谢您的建议。
    • 非常感谢VBasic2008的解释和建议。总的来说,感谢非常好的解释,user9601310,这就是我需要的,一个可以减少我的代码的表单,其中包含很多变量。对于此工作区中的所有合作伙伴,这是最后一个问题。正如我之前所说,我是 VBA 的初学者,但是,为什么要使用点“。”在财产之前?在这种情况下,“.Range”或“.Cells”。如果我在您向我展示代码时编写代码,VBA 会向我显示有关无效引用的错误。再次感谢大家!
    • .Range 和 .Cells(应该!!)在 With ... End with 的范围内有效。如果您没有这些,那么该点将不起作用。从本质上讲,使用 With ... 可以让您引用属性而无需重复“ThisWorkbook.Sheets("Sheet1")”。否则,您必须指定 ThisWorkbook.Sheets("Sheet1").Range、ThisWorkbook.Sheets("Sheet1").Cells 等。在这个特定示例中,只有两个使用点表示法的地方,您可以说不使用“With”并完全限定每一行。当有更长的代码块时,它会更有用。
    猜你喜欢
    • 2013-12-12
    • 2011-04-21
    • 2022-01-12
    • 2019-10-14
    • 2020-11-15
    • 2021-03-23
    • 1970-01-01
    • 2022-01-05
    • 2022-01-26
    相关资源
    最近更新 更多