1

UPDATE: I have been reading some websites and forums about passing arrays between subs and functions. But it got me thinking about whether my variable declarations were the problem? Currently all of my arrays (Results1,2,3,FinalResults, X & Y) are all being declared as variant. And I think this may cause a problem when passing arrays between functions. Anyone know if this problem will pertain to my code? ALso, just to clarify I want the values in Results1,2,3 to pass into the function.

I keep getting 'subscript out of range' when I try to run the following function in VBA. Both X and Y are 1-dimensional arrays that I am trying to merge data into a new array. The error occurs when I try to specify the lower and upper bounds for array X.

Function lnArray(X() As Variant, Y() As Variant) As Variant
Dim counter1 As Long
Dim xcount As Long
Dim t As Long
Dim FinalResults() As Variant

counter1 = 0
    For xcount = LBound(X) To UBound(X)
        On Error Resume Next
        t = Application.Match(X(xcount, 1), Y, 0)
        If Err.Number = 0 Then
            If (t > 0) Then
                counter1 = counter1 + 1
                ReDim Preserve FinalResults(counter1)
                FinalResults(counter1) = X(xcount, 1)
            End If
        End If
        On Error GoTo 0
    Next xcount

lnArray = FinalResults
End Function

Update - This is the current code I have right now, I've made a few corrections. Namely making sure the arrays are passed to the function by reference and changed everything into a 1-dimensional array. However the same problem still persists. I've checked and my Results1() and Results2() array both store values but it is not being passed to my UDF X() and Y() variable. I included the portion of the code in my sub that passes the function, please take a look.

Sub search()
Dim Results1() As Variant, Results2() As Variant, FinalResults() As Variant

        FinalResults = lnArray(Results1, Results2)
End Sub

Function lnArray(ByRef X() As Variant, ByRef Y() As Variant) As Variant
Dim counter1 As Long
Dim xcount As Long
Dim t As Long
Dim FinalResults() As Variant

counter1 = 0
    For xcount = LBound(X) To UBound(X)
        On Error Resume Next
        t = 0
        t = Application.Match(X(xcount), Y, 0)
        If Err.Number = 0 Then
            If (t > 0) Then
                counter1 = counter1 + 1
                ReDim Preserve FinalResults(counter1)
                FinalResults(counter1) = X(xcount)
            End If
        End If
        On Error GoTo 0
    Next xcount

lnArray = FinalResults
End Function

Edit - The following is how I populate data for my Results1() and Results2() array. Please let me know if more information is required.

Sub Search()

Dim TextBox1 As Long
Dim TextBox3 As Long
Dim Results1() As Variant
Dim Results2() As Variant
Dim FindRange1 As Range
Dim Find1 As Range
Dim FindRange2 As Range
Dim Find2 As Range
Dim i1 As Long
Dim i2 As Long

TextBox1 = ILsearch.TextBox1.Value
TextBox3 = ILsearch.TextBox3.Value

 Set FindRange1 = Worksheets("Properties").Range("P7:P1000")
            If ILsearch.P1B1.Value = True Then
                For Each Find1 In FindRange1
                    If (Find1.Value < TextBox1) And (Find1.Value > 0) Then
                        i1 = i1 + 1
                        ReDim Preserve Results1(i1)
                        Results1(i1) = Find1.Address
                    End If
                Next Find1
            End If

 Set FindRange2 = Worksheets("Properties").Range("P7:P1000")
            If ILsearch.P2B1.Value = True Then
                For Each Find2 In FindRange2
                    If (Find2.Value < TextBox3) And (Find2.Value > 0) Then
                        i2 = i2 + 1
                        ReDim Preserve Results2(i2)
                        Results2(i2) = Find2.Address
                    End If
                Next Find2
            End If
End Sub

Edit2 - This is currently how I'm choosing which arrays to consolidate and display in my results. I have 3 search variables (Results1,2 and 3) and if only 1 is selected, displaying it is easy. However depending on which variables are selected I also need to consolidate the arrays (1+2,1+3,2+3, or all 3 arrays) . I realize how cluttered it is and inefficient it probably is but I could not come up with a better way.

'For a single property selection
Dim p1results As Range
Dim shProperties As Worksheet
Dim shSearchResult As Worksheet

Set shProperties = ActiveWorkbook.Worksheets("properties")
Set shSearchResult = ActiveWorkbook.Worksheets("searchresult")

If (ILsearch.ComboBox1.Enabled = True) And (ILsearch.ComboBox2.Enabled = False) And (ILsearch.ComboBox3.Enabled = False) Then
   On Error Resume Next
   For i1 = LBound(Results1) To UBound(Results1)
        Set NextRow = shSearchResult.Cells(shSearchResult.Rows.Count, 4).End(xlUp).Offset(1, -3)
        shProperties.Range(Results1(i1)).EntireRow.Copy NextRow
    Next i1
End If

'repeat same if/then code for Results2 and Results3

Dim FinalResults() As Variant
Dim FinCount As Integer
Dim Counter1 As Long
Dim t As Long

If (ILsearch.ComboBox1.Enabled = True) And (ILsearch.ComboBox2.Enabled = True) And (ILsearch.ComboBox2.Enabled = False) Then
    If IsArrayAllocated(Results1) = True And IsArrayAllocated(Results2) = True Then
    Else
         Debug.Print "Empty Array"
    End If

    FinalResults = lnArray(Results1, Results2)
        On Error Resume Next
        For FinCount = LBound(FinalResults) To UBound(FinalResults)
            Set NextRow = shSearchResult.Cells(shSearchResult.Rows.Count, 4).End(xlUp).Offset(1, -3)
            shProperties.Range(Results3(i3)).EntireRow.Copy NextRow
        Next FinCount
End If
'repeat same if/then for (1+3) arrangement and (2+3)arrangement

Dim intResults() As Variant

If (ILsearch.ComboBox1.Enabled = True) And (ILsearch.ComboBox2.Enabled = True) And (ILsearch.ComboBox2.Enabled = True) Then
intResults = lnArray(Results1, Results2)
FinalResults = lnArray(intResults, Results3)
    On Error Resume Next
    For FinCount = LBound(FinalResults) To UBound(FinalResults)
        Set NextRow = shSearchResult.Cells(shSearchResult.Rows.Count, 4).End(xlUp).Offset(1, -3)
        shProperties.Range(Results3(i3)).EntireRow.Copy NextRow
    Next FinCount
End If
  • counters should be integer (counter1 and xcount). can you show us what are X() and Y() ? what do you see when you debug ? please tell us what you *wanted* to do, there might be a better way (as discussed here : http://stackoverflow.com/questions/6503300/vba-intersect-vs-match-method/) – JMax Jun 28 '11 at 09:33
  • can you also tell us what is the error you get and on which line ? – JMax Jun 28 '11 at 09:42
  • The error I get is 'subscript is out of range' on the line "xcount=Lbound(X) to UBound(X)" so unless the function isn't recognizing X as an array I don't understand how I can be incorrectly sizing my array X. X and Y are dynamic arrays that contains the cell addresses of a search function based off of different search variables. So the bounds of X and Y arrays vary. –  Jun 28 '11 at 09:52
  • @JMax: "counters should be integer" Are you saying that counters should be `Integer` rather than `Long`? This is plain false. In fact, it's much better to use `Long` by convention. This assures that if the array size grows past 32767 elements, the program that the index variable can still address all elements in the array. – Jean-François Corbett Jun 28 '11 at 10:22
  • @Jean-François Corbett: my mistake, i take the point. Thanks for correcting me – JMax Jun 28 '11 at 11:47

5 Answers5

1

Sounds like X is not an array: try showing the VBE Locals window to see what X really is

Charles Williams
  • 23,121
  • 5
  • 38
  • 38
  • I ran the local windows and X is being defined as a variant() but the values from my arrays in the sub (Results1() and Results2()) are not being carried over into my lnArray function X() and Y(). All of my arrays are defined as variants and I want the values to pass between the functions. Any suggestions on what might be wrong? –  Jun 29 '11 at 07:15
1

There is a mixed message in your code:

You state, and your line of code For xcount = LBound(X) To UBound(X) expects 1 dimensional arrays

But, Application.Match(X(xcount, 1), Y, 0) implies two or more dimensions (the , 1 bit). This is supported by the error, which will be returned if X is in fact two dimensional.

When the code runs and errors, examine X in the watch window to determine its true form

EDIT see Phydaux's comment - LBound(X) defaults to dimension 1 of a multi-dimensional array.

EDIT2

Two potential issues:

If either P1B1 or P2B1 = FALSE, or no matches are found in the data, then Results1 or Results2 respectively are never dimensioned. Calling LBound or UBound on a undimensioned array will cause the error

Believe it or not, calling X(xcount, 1) on a one dimensional array errors. But since On Error Resume Next is active, the error is not reported.

So, you need to:

  • Handle the case where X or Y are not dimensioned

  • Drop the ,1 from X(xcount, 1)

I suggest you look at Chip Pearson's excellent site for array handling code

Community
  • 1
  • 1
chris neilsen
  • 52,446
  • 10
  • 84
  • 123
  • @Chris Neilsen hey thanks for the help again, I took out the ( ,1) and made my FinalResults() into a 1-dimensional array but the problem persists. Is my approach to this problem just inefficient and I should just start over instead? This is the last piece of program that I need to debug to get my program to work... –  Jun 28 '11 at 10:28
  • @ren: did you run the Watch test? what was the result? The `subscript is out of range` error tells you X is _not_ a one dimensional array. – chris neilsen Jun 28 '11 at 10:31
  • @Chris Neilsen what do you mean a Watch test? sorry..still relatively new to VBA. You mean just debug it line by line? –  Jun 28 '11 at 10:42
  • When you run your code and it pops up the error window, click debug. You'll be in break mode with the line that caused the error highlighted yellow. If its in `lnArray`, right click an instance of X and select Add Watch... In the watch window what does it say for X under Type? You can also check the values in X to see if your search worked as expected. – chris neilsen Jun 28 '11 at 10:49
  • @Chris Neilsen thanks for the awesome tip! that really helped me catch some bugs in my program really quickly. But I am still getting the same error. It seems that my arrays from my sub is not getting passed into my UDF. The arrays from my sub is called "Results1() and Results2()" and it is supposed to get passed into the function as X() and Y(). Any tips? –  Jun 28 '11 at 11:19
  • 3
    @chris neilsen, LBound(x) or UBound(x) are both perfectly fine for multi-dimensional arrays. From the VB refrence: `LBound(arrayname[, dimension])` Where "If `dimension` is omitted, 1 is assumed." – Chris Kent Jun 28 '11 at 11:58
  • @ren you still havn't told us the actual type of `X` and `Y`. In your sub `Search` there must be some code that sets the dimensions of `Results1` and `Results2`. Post the relavent code. Until you do we really are only guessing – chris neilsen Jun 28 '11 at 11:59
  • @Phydaux you're right. So, maybe X is undimensioned when lnArray is called. We need more info! – chris neilsen Jun 28 '11 at 12:05
  • Ok I've just updated my code above to show how Results1() and Results2() is populated. It is a search function that searches for matches from a range of data specified by the user and stores the cell addresses in Results1() and Results2(). User can search using multipl variables so I want to consolidate Results1 and Results2 into a new array to display only matches that show up in both arrays. Let me know if more explanation is required. –  Jun 28 '11 at 12:13
  • @Christ neilsen you bring up an excellent point on if the search function returns no results or if the radio dials aren't selected. In which case I can just redim my Results1/2 array into "0" in my code. However, I am not sure if this address my problem. When I run my sub the Watch window is showing that there are values stored in my Results1() and Results2() array. However, these values are not being forwarded into my X() array in the function. Since my Results() arrays are dimensioned I shouldn't encounter the 1st error you suggested. Or am I wrong? –  Jun 28 '11 at 12:59
  • @ren I have not been able to replicate a case where `Results1/2` are dimensioned and `X/Y` are not once lnArray is called. So far as i can tell this should never occur – chris neilsen Jun 28 '11 at 13:06
  • @Chris Neilsen what an interesting predicament I have. My actual code is much longer but it goes through the same sequence as what I suggested above. I guess I will have to go through line by line to find the error. For some reason my arrays aren't being carried over to my function at all. –  Jun 28 '11 at 13:41
1

programming with on error resume next may be difficult to debug. This part of the code will only work for one error occurence.

For xcount = LBound(X) To UBound(X)
    On Error Resume Next
    t = 0
    t = Application.Match(X(xcount), Y, 0)
    If Err.Number = 0 Then
        If (t > 0) Then

When the first error occur the If Err.Number = 0 will fail for all of the remaining iterations. To avoid this, you should reset error with Err.clear

For xcount = LBound(X) To UBound(X)
    On Error Resume Next
    t = 0
    t = Application.Match(X(xcount), Y, 0)
    If Err.Number <> 0 Then 
        Err.clear 'ignore match error
    Else
        If (t > 0) Then

Finally you can extend this approach by adding logging before Err.Clear for example:

debug.print Err.number,Err.message....
Frederic Bazin
  • 1,530
  • 12
  • 27
0

To check if your match worked, you'd better use :

t = Application.Match(X(xcount, 1), Y, 0)
If IsEmpty(t) Then
   counter1 = counter1 + 1
End If

Depending if you need also to test if your t > 0

JMax
  • 26,109
  • 12
  • 69
  • 88
  • 1
    `!=` is not VBA syntax. Depending upon the type of variable t you would need something like `IsEmpty(t)` or `t <> vbnullstring` –  Jun 28 '11 at 09:56
  • @osknows: thanks ! sorry, i mixed up languages. i will update my post so that this error will not remain for next readers – JMax Jun 28 '11 at 10:17
0

EDIT: The problem appears to be that the function could be called when the arrays are not allocated. This could happen if there are no matches or if ILsearch.P1B1.Value = False or ILsearch.P2B1.Value = False.

I've added a function which checks if the arrays are allocated

Sub Search()

Dim TextBox1 As Long
Dim TextBox3 As Long
Dim Results1() As Variant
Dim Results2() As Variant
Dim FindRange1 As Range
Dim Find1 As Range
Dim FindRange2 As Range
Dim Find2 As Range
Dim i1 As Long
Dim i2 As Long

TextBox1 = ILsearch.TextBox1.Value
TextBox3 = ILsearch.TextBox3.Value

 Set FindRange1 = Worksheets("Properties").Range("P7:P1000")
            If ILsearch.P1B1.Value = True Then
                For Each Find1 In FindRange1
                    If (Find1.Value < TextBox1) And (Find1.Value > 0) Then
                        i1 = i1 + 1
                        ReDim Preserve Results1(i1)
                        Results1(i1) = Find1.Address
                    End If
                Next Find1
            End If

 Set FindRange2 = Worksheets("Properties").Range("P7:P1000")
            If ILsearch.P2B1.Value = True Then
                For Each Find2 In FindRange2
                    If (Find2.Value < TextBox3) And (Find2.Value > 0) Then
                        i2 = i2 + 1
                        ReDim Preserve Results2(i2)
                        Results2(i2) = Find2.Address
                    End If
                Next Find2
            End If
If IsArrayAllocated(Results1) = True And _
    IsArrayAllocated(Results2) = True Then
    Z = lnArray(Results1, Results2)
Else
    Debug.Print "Empty Array"
End If
End Sub


Function lnArray(X() As Variant, Y() As Variant) As Variant
Dim counter1 As Long
Dim xcount As Long
Dim t As Long
Dim FinalResults() As Variant

counter1 = 0
    For xcount = LBound(X) To UBound(X)
        On Error Resume Next
        t = 0
        t = Application.Match(X(xcount), Y, 0)
            If (t > 0) Then
                counter1 = counter1 + 1
                ReDim Preserve FinalResults(counter1)
                FinalResults(counter1) = X(xcount)
        End If
        On Error GoTo 0
    Next xcount

lnArray = FinalResults
End Function

Function IsArrayAllocated(Arr As Variant) As Boolean
'**Determines whether an array is allocated to avoid UBound errors
    On Error Resume Next
    IsArrayAllocated = IsArray(Arr) And _
                       Not IsError(LBound(Arr, 1)) And _
                       LBound(Arr, 1) <= UBound(Arr, 1)
    On Error GoTo 0
End Function
Community
  • 1
  • 1
  • @Osknos Sorry if this seems like a stupid question but I'm just trying to understand the sytax here...what is the point of transposing the ranges/arrays X and Y from the sub? –  Jun 28 '11 at 11:11
  • Loading an array directly from an Excel range gives a 2d array (row,column). I've just used it as a quick way to load a 1d array in this case. –  Jun 28 '11 at 11:19
  • Thanks! So since I have 1-dimensional arrays generated from my sub this shouldnt be a problem for me correct? –  Jun 28 '11 at 11:25
  • You code `X(xcount, 1)` is referencing X as a 2 dimensional array. `X(xcount)` references X as a 1d array. So, yes Application.Transpose is not required if X is already 1d. –  Jun 28 '11 at 11:28
  • My array from my sub seems to pass to my X and Y arrays in my function still. Do you have any idea why this might be? I've updated my code above. –  Jun 28 '11 at 11:49
  • `Dim Results1() As Variant`, `Results2() As Variant` they're dimensioned now but there's nothing in them. They're empty arrays. Put some values in them before passing to the function. –  Jun 28 '11 at 11:54
  • They do have values, the Watch window shows that there are values for the arrays Results1() and Results2() from the sub I wrote. and I have tested each array individually by displaying the answers and both have values. –  Jun 28 '11 at 11:57
  • Update your question above to show how you fill arrays Results1() and Results2() –  Jun 28 '11 at 12:01
  • Thanks for the helpful code osknows, the same problem keeps persisting however. Even though my arrays are dimensioned from the sub, the values in the array arent being carried over the the arrays in the function. I am quickly running out of ideas on why this might be! –  Jun 28 '11 at 13:42
  • Check to make sure your not using Dim/Redim elsewhere? –  Jun 28 '11 at 13:44
  • I don't think so. However my problem may lie in the fact that I essentially have 3 search boxes that allows the user to search for 3 types of variables in each. So the number of Results arrays that I need to consolidate vary. I have tried to account for this by writing a series of if/then statements so that "If only Results1 is selected the only Results1 array is displayed" so I essentially have 7 different if/then statements to account for(1 only, 2 only, 3only, 1 + 3, 1+2, 2+3, and all 3 arrays at once). would this affect my arrays in anyways? I'll post my code up above. –  Jun 28 '11 at 14:05