0

Is there a simple way to implement a loop until each value in a multidimensional array is not "empty" per the type - so loop until a string array is filled with values that are not empty strings, etc.

The pseudocode example of what I'm going for:

 Dim MultiArray(100,100) As String

 Do Until MultiArray(0,0) To MultiArray (100,100) Is Not = ""
      'Operations
 Loop
Community
  • 1
  • 1
  • 1
    The upper and lower bounds of every single dimension of your array would be known before you even enter the loop. An array is never "empty" or "full" - either it's initialized, or it isn't. FWIW this isn't how `Null` is used in VBA. – Mathieu Guindon Oct 24 '17 at 15:39
  • Thanks Mat's Mug, I meant whether or not the array was filled with nothing or if it was filled with any actual values. Maybe it would have been better if I had written Do Until MultiArray(0,0) To MultiArray (100,100) = "". Changed to reflect that. –  Oct 24 '17 at 15:51
  • It's always "filled with values" - if you've initialized an array, every single cell of that array contains the array type's default value. e.g. `Dim foo(1 To 10) As String` makes an array that contains 10 empty strings. `Dim foo(1 To 10) As Long` makes an array that contains 10 `0` values, because `0` is what a `Long` variable initializes to. A `Variant` array initializes with `vbEmpty` values, an object array initializes with `Nothing` object references, and so on. Your question (and see, its answer) has nothing to do with the array's contents at all. – Mathieu Guindon Oct 24 '17 at 15:54
  • Then the implied intention is to loop until there are no empty strings, no 0 values, or no vbEmpty values depending on the array type. It very much does have to do with the contents, I want the loop to stop when the contents are no longer empty strings, 0 values, or vbEmpty depending on the type. –  Oct 24 '17 at 15:57
  • Agreed, I just re-read the answer and had to uncheck it. But it doesn't deserve the downvote due to your misinterpretation of what I said. I can make it clearer if needed, and will do so now. It was very clear to me what I was going for and still is now. I will clarify the post. –  Oct 24 '17 at 15:59
  • Read [mcve] for help about including code that properly illustrates the problem you're trying to solve. The pseudo-code you included isn't even valid VBA code - might be clear *for you*, but someone that isn't in your head can't possibly guess what that illegal code is supposed to be doing. Proof: below answer. – Mathieu Guindon Oct 24 '17 at 16:00
  • I'm reading, Mat's Mug, but how does this apply when there is no active code yet, but the question is about how to do something that you have no working solution for yet? –  Oct 24 '17 at 16:02
  • Seems like an X-Y problem. You want to solve X, but you're asking about Y. For all I know you might actually be needing a way to get the last row in an Excel worksheet - but that's completely not what you're asking. – Mathieu Guindon Oct 24 '17 at 16:03
  • I changed the code to clarify the question per Mat Mug's questioning, let me know if it needs further clarification. –  Oct 24 '17 at 16:04
  • Copy the array into a variant, redim the copy down to a single element and that element will have the default value for the type of the original array. Check the contents of your original array against that default value to see if it's "empty". – Tim Williams Oct 24 '17 at 16:25
  • Thanks, Tim! That makes sense. I was considering writing a loop that would check against the "empty value", but was wondering if there was a faster way than looping and testing each value against the relative "empty" value. For a 100,100 array that's a lot of calculations to do each time I loop just to verify if the values are all "not empty". I was wondering if there was any native element in VBA that already detects whether or not an array contains all empty values of its type, all "non empty" values of it's type, etc. so that the loop could run until "all are not empty" was True. –  Oct 24 '17 at 16:32
  • No there's nothing like that. Runtime-wise 100x100 is nothing though. – Tim Williams Oct 24 '17 at 16:33
  • Ok, thanks Tim! Nice to know, I'll just do it manually. –  Oct 24 '17 at 16:57
  • your question is actually `Is there a way to loop until a multidimensional array no longer contains a specific value?` ..... use a `flag` variable, something like `dim allFull as boolean` ... then use this `do until allFull` .... have code inside the loop that checks the array and sets the flag if all values meet the specific criteria. `allFull = true` – jsotola Oct 24 '17 at 17:36
  • Hi jsotola, thanks for the response. That makes sense now that I know a bit more. I actually posted a similar comment under Mat's Mug's answer. I originally posted thinking there may have been an element in excel that already tested true or false if an array was "full" or "empty" (meaning not containing empty values of it's own type). –  Oct 24 '17 at 17:55

2 Answers2

2

Is this "simple"?

For i = 0 To 100

    For j = 0 To 100

        'Operations
        MultiArray(i, j) = 1

    Next j

Next i

Edit

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

Note that this is a very expensive function, as it will attempt to iterate through the entire array every time it checks, i.e. it gets progressively slower as the array is filled. I'm unsure why you need to check for empty strings and why you can't simply iterate through the array once. However, this is the only way that I know to do what you're asking.

Tigregalis
  • 607
  • 3
  • 11
  • Thank you for actually answering and not down-voting my question, Tigregalis! I completely blanked that I could just iterate through it like this. Thank you! –  Oct 24 '17 at 15:53
  • Sorry, had to uncheck this Tigregalis. I just realized that this would not test for whether or not the values had been filled, but would just iterate through the array. Thanks anyway! –  Oct 24 '17 at 16:00
  • I don't quite understand the logic. What is the use case? What problem are you actually trying to solve? I'll edit my answer based on what I *think* you're trying to do, but I don't understand why you'd want to do this. – Tigregalis Oct 25 '17 at 11:39
  • Awesome, thanks Tigregalis! I actually concocted similar code after reading Mat's Mugs answer. I'm cycling through data on a worksheet and filling arrays based on certain criteria and once the arrays are all filled I will then proceed to process the data in them. That's the "generalized" use case without getting too much in the weeds. I also considered another approach of flagging each array after the last indice is filled, so I may use either. Thanks again for persisting! –  Oct 25 '17 at 15:33
  • Yes, the original question is in part due to the fact that I understood it was going to be expensive. I thought perhaps VBA would have already had some way of determining a wholly filled or completely "empty" array without needing to cycle through it like this, which is exactly why I am now considering just flagging each array once the last index is not an empty string. –  Oct 25 '17 at 15:35
1

You have a 2D array, so the only possible loop construct that will iterate all values is a nested For loop.

If I understand your problem statement correctly, you want to break out of that nested loop when you encounter an empty string value.

That's making a lot of assumptions about what's actually in that array. Let's start by assuming a row/column layout, respectively in dimension indices 1 and 2 - and because we don't know where the data came from (a worksheet range? some file? hard-coded?), let's not hard-code the lower and upper bounds of the loops:

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

There's a problem though: this will break out of the loop as soon as an empty string is encountered - which may or may not be what you wanted.

If you want to stop iterating rows when you found a row where every column contains an empty string, then this isn't it. You need more precise logic. Something like this:

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

Note that both of these loops will blow up if any "cell" contains an error value. You can guard against that using the IsError function.

But then again, this is assuming you're iterating rows. And if you're in Excel and you're iterating a 2D array where the first dimension represents rows, and you're looking to stop a loop once you've found a "row" that contains nothing but empty "cells", then the real problem you're trying to solve is "find the last used row in a range", and you're doing all this for nothing and this answer is what you really want to use:

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

I could keep extrapolating about what you're really trying to achieve all day, but I'll stop here.

Mathieu Guindon
  • 69,817
  • 8
  • 107
  • 235
  • Thanks, Mat's Mug! I'm going to read through again more thoroughly and apply this. The intention was exit the loop once there are NO "empties" in the array - meaning, break from the loop once the entire array is filled with "non-empty" values. From what you wrote it seems like I could use the same method. My first thought is using LBound and UBound statements like you have and set a boolean called IsCompletelyFull (for instance) False every time it finds an "empty" and then once the boolean remains "True" after iterating through the entire array then exit the loop. –  Oct 24 '17 at 17:21