【问题标题】:Is there a way to loop until a multidimensional array is full in VBA?有没有办法循环直到多维数组在 VBA 中已满?
【发布时间】:2018-04-05 11:43:58
【问题描述】:

有没有一种简单的方法来实现一个循环,直到多维数组中的每个值都不是每个类型的“空” - 所以循环直到字符串数组被非空字符串的值填充,等等。

我要做的伪代码示例:

 Dim MultiArray(100,100) As String

 Do Until MultiArray(0,0) To MultiArray (100,100) Is Not = ""
      'Operations
 Loop

【问题讨论】:

  • 在您进入循环之前,您的数组的每个维度的上限和下限都将是已知的。一个数组永远不会是“空的”或“满的”——要么它被初始化,要么它没有被初始化。 FWIW 这不是在 VBA 中使用 Null 的方式。
  • 感谢 Mat's Mug,我的意思是数组是否填充了任何内容或填充了任何实际值。如果我将 Do until MultiArray(0,0) To MultiArray (100,100) = "" 写出来,可能会更好。更改以反映这一点。
  • 它总是“充满值”——如果你已经初始化了一个数组,那么该数组的每个单元格都包含数组类型的默认值。例如Dim foo(1 To 10) As String 创建一个包含 10 个空字符串的数组。 Dim foo(1 To 10) As Long 创建一个包含 10 个 0 值的数组,因为 0Long 变量初始化的对象。一个Variant 数组用vbEmpty 值初始化,一个对象数组用Nothing 对象引用初始化,等等。您的问题(并查看其答案)与数组的内容完全无关。
  • 那么隐含的意图是循环直到没有空字符串、没有 0 值或没有 vbEmpty 值,具体取决于数组类型。它确实与内容有关,我希望当内容不再是空字符串、0 值或 vbEmpty 时停止循环,具体取决于类型。
  • 同意,我只是重新阅读了答案,不得不取消选中它。但是由于您对我所说的话的误解,它不值得被否决。如果需要,我可以更清楚地说明,现在会这样做。我很清楚我的目标是什么,现在仍然如此。我会澄清这个帖子。

标签: vba excel loops multidimensional-array


【解决方案1】:

这“简单”吗?

For i = 0 To 100

    For j = 0 To 100

        'Operations
        MultiArray(i, j) = 1

    Next j

Next i

编辑

Function IsArrayFilled(ByRef Multi_Array() As String) As Boolean

    Dim i As Long, j As Long

    For i = LBound(Multi_Array, 1) To UBound(Multi_Array, 1)

        For j = LBound(Multi_Array, 2) To UBound(Multi_Array, 2)

            If Multi_Array(i, j) = "" Then ' If there are ANY blank strings, then terminate the function immediately and return false

                IsArrayFilled = False
                Exit Function

            End If

        Next j

    Next i

    ' If we got through the whole array without finding any blank strings, then return true
    IsArrayFilled = True

End Function

Sub Test()

    Dim MultiArray(0 To 100, 0 To 100) As String

    Do While Not IsArrayFilled(MultiArray)

        'Operations

    Loop

End Sub

请注意,这是一个非常昂贵的函数,因为它会在每次检查时尝试遍历整个数组,即随着数组被填满,它会逐渐变慢。我不确定为什么需要检查空字符串以及为什么不能简单地遍历数组一次。但是,这是我知道的唯一方法,可以满足您的要求。

【讨论】:

  • 感谢您实际回答而不是否决我的问题,Tigregalis!我完全不知道我可以像这样迭代它。谢谢!
  • 抱歉,必须取消选中这个 Tigregalis。我刚刚意识到这不会测试值是否已被填充,而只会遍历数组。还是谢谢!
  • 我不太明白其中的逻辑。用例是什么?你真正想解决什么问题?我将根据我认为您尝试做的事情来编辑我的答案,但我不明白您为什么要这样做。
  • 太棒了,感谢 Tigregalis!在阅读了 Mat's Mugs 的答案后,我实际上编写了类似的代码。我正在循环浏览工作表上的数据并根据某些标准填充数组,一旦数组全部填充完毕,我将继续处理其中的数据。这是“通用”用例,没有太多杂草。我还考虑了在填充最后一个索引后标记每个数组的另一种方法,因此我可以使用其中任何一种。再次感谢您的坚持!
  • 是的,最初的问题部分是因为我知道它会很昂贵。我想也许 VBA 已经有某种方法可以确定一个完全填充或完全“空”的数组,而无需像这样循环遍历它,这正是我现在考虑在最后一个索引不为空时标记每个数组的原因字符串。
【解决方案2】:

您有一个 2D 数组,因此唯一可能迭代所有值的循环构造是 nested For loop

如果我正确理解了您的问题陈述,您希望在遇到空字符串值时跳出嵌套循环。

这对 该数组中的实际内容做了很多假设。让我们首先假设一个行/列布局,分别在维度索引 1 和 2 中 - 因为我们不知道数据来自哪里(工作表范围?某个文件?硬编码?),我们不要硬编码循环的上下界:

Dim row As Long
For row = LBound(data, 1) To UBound(data, 1)

    Dim break As Boolean
    Dim col As Long
    For col = LBound(data, 2) To UBound(data, 2)

        'Operations

        Dim value As Variant
        value = CStr(data(row, col))

        If value = vbNullString Then
            break = True
            Exit For
        End If

    Next
    If break Then Exit For
Next

但有一个问题:只要遇到一个空字符串,它就会跳出循环——这可能是也可能不是你想要的。

如果您想在发现每一列都包含一个空字符串的行时停止迭代行,那么不是这样。你需要更精确的逻辑。像这样的:

Dim row As Long
For row = LBound(data, 1) To UBound(data, 1)

    Dim rowContents As String
    Dim col As Long
    For col = LBound(data, 2) To UBound(data, 2)

        'Operations

        rowContents = rowContents & CStr(data(row, col))

    Next
    If Strings.Trim(rowContents) = vbNullString Then Exit For
Next

请注意,如果任何“单元格”包含错误值,这两个循环都会崩溃。您可以使用IsError 函数来防止这种情况发生。

但话又说回来,这是假设您正在迭代。如果您在 Excel 中并且正在迭代一个二维数组,其中第一个维度表示行,并且您希望在找到一个只包含空“单元格”的“行”时停止循环,那么你试图解决的真正问题是“在一个范围内找到最后使用的行”,而你所做的一切都是徒劳的,this answer 是你真正 em> 想用:

With Sheets("Sheet1")
    If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
        lastrow = .Cells.Find(What:="*", _
                      After:=.Range("A1"), _
                      Lookat:=xlPart, _
                      LookIn:=xlFormulas, _
                      SearchOrder:=xlByRows, _
                      SearchDirection:=xlPrevious, _
                      MatchCase:=False).Row
    Else
        lastrow = 1
    End If
End With

我可以继续推断你整天真正想要实现的目标,但我会停在这里。

【讨论】:

  • 谢谢,马特的马克杯!我将再次更彻底地阅读并应用它。意图是一旦数组中没有“空”就退出循环 - 意思是,一旦整个数组充满“非空”值,就退出循环。从您写的内容看来,我可以使用相同的方法。我的第一个想法是像你一样使用 LBound 和 UBound 语句,并在每次找到“空”时设置一个名为 IsCompletelyFull 的布尔值(例如)False,然后一旦布尔值在遍历整个数组后保持“真”,然后退出循环.
猜你喜欢
  • 2021-08-10
  • 2016-05-26
  • 1970-01-01
  • 1970-01-01
  • 2021-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多