Array has no value after being passed ByRef to sub - arrays

I have a module in a worksheet that is supposed to pass an array to another sub in the same module. So far, I've noticed that the variable N which is being used to to pull each individual array element always says 0 in the watch window, how do I get my elements out of the array? Here is the code:
Option Explicit
Sub CreateReports()
Dim numRows As Integer
Dim numCount As Integer
Dim category As String
Dim size As Integer
Dim sizeCount As Integer
Dim departmentNums() As Integer
With Sheets("GM Alignment")
numRows = Application.WorksheetFunction.CountA(Range("A2:A1048576"))
.Range("A2").Select
Do While numCount < numRows
category = ActiveCell.Value
size = Range(ActiveCell.Offset(0, 1), ActiveCell.Offset(0, 1).End(xlToRight)).Columns.Count - 1
If size > 7 Then
size = 0
End If
ReDim departmentNums(size)
.Cells(ActiveCell.Row, 1).Select
For sizeCount = 0 To size
ActiveCell.Offset(0, 1).Select
departmentNums(sizeCount) = ActiveCell.Value
Next sizeCount
.Cells(ActiveCell.Row, 1).Select
GenerateReports Arr:=departmentNums, Sheet:=category
ActiveCell.Offset(1, 0).Select
numCount = numCount + 1
Loop
End With
End Sub
Sub GenerateReports(ByRef Arr() As Integer, Sheet As String)
Dim N As Integer
For N = LBound(Arr) To UBound(Arr)
Dim Lastrow As Long
With Sheets("DATA")
If .Range("I:I").Find(N, , xlValues, xlWhole, , , False) Is Nothing Then
MsgBox "No " + Sheet + " rows found. ", , "No Rows Copied": Exit Sub
Else
Application.ScreenUpdating = False
Lastrow = .Range("K" & Rows.Count).End(xlUp).Row
.Range("K1:K" & Lastrow).AutoFilter Field:=1, Criteria1:=N
.Range("K2:K" & Lastrow).SpecialCells(xlCellTypeVisible).EntireRow.Copy
Sheets(Sheet).Range("A2").PasteSpecial xlPasteValues, xlPasteSpecialOperationNone, False, False
.AutoFilterMode = False
'Position on cell A3
With Application
.CutCopyMode = False
.Goto Sheets("DATA").Range("A2")
.ScreenUpdating = True
End With
MsgBox "All matching data has been copied.", , "Copy Complete"
End If
End With
Next N
End Sub
Thanks!

Not really looking too far into your code but I noticed that at no point do you read from or assign to Arr in GenerateReports. I believe you are misunderstanding how Arrays behave.
Dim index as Integer
For index = LBound(Arr) To UBound(Arr)
Debug.Print "Index: "; index; " Value: " Arr(index)
Next N
LBound(Arr) and Ubound(Arr) return the lowest and highest index of Arr not the values. In order to access the values contained in Arr use Arr(index).
If you don't care about the index you can use
Dim element as Integer
For each element in Arr
debug.Print element
Next n
It is recommended to use this method whenever possible, as it allows for other sequence's to be used such as Collection. However, it is not always possible such as when you are iterating over multiple sequences or parts of a sequence.
Here is a basic example:
Sub PrintOneToTen()
Dim xs(1 to 10) as Integer
FillArray xs
Dim x as Integer
For Each x In xs
Debug.Print x
Next x
' or just Debug.Print Join(xs, vbNewLine)
End Sub
Sub FillArray(ByRef xs() As Integer)
Dim i as Integer
For i = LBound(xs) To Ubound(xs)
xs(i) = i
Next i
End Sub
Documentation for VB.NET Arrays is listed here. Note VB.NET is not VBA, but as far as arrays are concerned 99% of the info there should be the same in VBA. I would post the VBA documentation but it's buried deep in Microsofts' database and I don't believe they care about it.

Related

VBA Search an array inside an array? (Check if all items of one array exists in another array)

IS it possible to look for an array of strings and/or integers inside an array of strings and/or integers? If so, then how?
To find a string in an array of strings I use code like:
If IsInArray(LowerFilmWidthArray, LowerFilmWidth) then
'Dos tuff
end if
And a function is:
Function IsInArray(arr As Variant, myVal As Variant) As Boolean
IsInArray = Not IsError(Application.Match(myVal, arr, 0))
Debug.Print (IsInArray)
End Function
As a result example, imagine you have an array of integers (1-10) and You are looking if your array (1,5,6) are inside that previous array (all items of it) and then return True. In my case I am getting all my to look for values in columns from 3rd to last column with data, which would make up my array that I try to find ALL items of in another array and return true or false.
An actual example:
Dim LowerFilmWidthArray
LowerFilmWidthArray = Application.Transpose(Evaluate("row(320:420)"))
Dim LowerFilmWidth As Integer
LowerFilmWidth = Array(ThisWorkbook.Worksheets("Machine Specification").Cells(320, 400,400,620)
'I get theese from a range and they might as well be strings and an undefined number of defined by 3 to last column with data
if isinarray(LowerFilmWidthArray,LowerFilmWidth) then
msgbox("Great Success!")
end if
Result in this one would be false because of that last "620" which is not inside the LowerFilmWidthArray.
EDITED:
Still can't get this to work and my gut says that there's way too many unnecessary things in the answers when I simply need to take each item from an array and try to find it in another and get "TRUE" only if all items I was looking for are present in a big array.
I have converted my to look for array (smaller one) to get the values from a set range that will always be a row from 3 to lastcolumn.
Dim LowerFilmWidth
LowerFilmWidth = ThisWorkbook.Worksheets("Machine Specification").Range(Cells(Cells.Find("Lower Film Width (mm)").Row, 3), Cells(Cells.Find("Lower Film Width (mm)").Row, LastColumn))
And I expect this part to make an array of all the values in cells in that range. Now I need to see if all those items / elements are present in:
Dim LowerFilmWidthArray
LowerFilmWidthArray = Application.Transpose(Evaluate("row(320:420)"))
So I use the suggested function:
Function arrElemInArray(arr As Variant, arrX As Variant) As Boolean
Dim i As Long, j As Long, boolFound As Boolean
For i = LBound(arrX) To UBound(arrX)
For j = LBound(arr) To UBound(arr)
If CStr(arr(j)) = CStr(arrX(i)) Then
boolFound = True: Exit For
End If
If Not boolFound Then arrElemInArray = False: Exit Function
Next j
Next i
arrElemInArray = True
Debug.Print (arrElemInArray)
End Function
and engage it using
If arrElemInArray(LowerFilmWidthArray, LowerFilmWidth) Then
msgbox("Great success!")
End If
The solution has to work both with integers and strings. I still can't get it to work as expected. Often it returns "True" no matter what, but it seems that it only checks the first item in smaller array against the big array.
This code in the edit returns "subscript out of range" error on "CStr(arrX(i))".
But the values in the sheet are as in the image
The full subroutine looks like this:
Sub Testing()
Dim LastColumn As Long
LastColumn = Cells(Cells.Find("Parameters", lookat:=xlWhole).Row, Columns.Count).End(xlToLeft).Column
Dim LowerFilmWidth
LowerFilmWidth = ThisWorkbook.Worksheets("Machine Specification").Range(Cells(Cells.Find("Lower Film Width (mm)").Row, 3), Cells(Cells.Find("Lower Film Width (mm)").Row, LastColumn))
Dim LowerFilmWidthArray
LowerFilmWidthArray = Application.Transpose(Evaluate("row(320:420)"))
If arrElemInArray(LowerFilmWidthArray, LowerFilmWidth) Then
MsgBox ("Great success!")
End If
End Sub
Workbook:
enter link description here
Please, look at the next example. Is this what you try accomplishing?
Sub testArrInArr()
Dim arr(), arr1(), arr2(), arr3(), arr4()
arr1 = Array(1, 2, 3): arr2 = Array(2, 3, 4)
arr3 = Array(3, 6, 5, 4): arr4 = Array(4, 5, 6)
arr = Array(arr1, arr2, arr3)
Debug.Print arrIsInArray(arr, arr2)
End Sub
Function arrIsInArray(arr As Variant, arrX As Variant) As Boolean
Dim i As Long, jArr As String
For i = LBound(arr) To UBound(arr)
If Join(arr(i)) = Join(arrX) Then arrIsInArray = True: Exit Function
Next i
End Function
Edited:
In order to test each array element if exists in another array, plese try the next way:
Sub tst2CheckArrElements()
Dim arr, arr1, arr2
arr = Split("1,2,3,4,5", ","): arr1 = Split("Sausage,Dog,Ship", ","): arr2 = Split("1,3,2", ",")
Debug.Print arrElemInArray(arr, arr1)
Debug.Print arrElemInArray(arr, arr2)
End Sub
Function arrElemInArray(arr As Variant, arrX As Variant) As Boolean
Dim i As Long, j As Long, boolFound As Boolean, mtch
If Not IsArray(arrX) Then
For j = LBound(arr) To UBound(arr)
If CStr(arr(j)) = CStr(arrX) Then arrElemInArray = True: Exit For
Next j
Exit Function
End If
For i = LBound(arrX) To UBound(arrX, 2)
For j = LBound(arr) To UBound(arr)
If CStr(arr(j)) = CStr(arrX(1, i)) Then
boolFound = True: Exit For
End If
Next j
If Not boolFound Then arrElemInArray = False: Exit Function
boolFound = False
Next i
arrElemInArray = True
End Function
Is Array In Array
Personalized Study
Change the number format of the cells containing the values to general or to a numeric format to make it work.
Option Explicit
Sub Testing()
Const sHeader As String = "Parameters"
Const sProperty As String = "Lower Film Width (mm)"
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim ws As Worksheet: Set ws = wb.Worksheets("Machine Specification")
' Reference the last cell of the used range.
Dim LastCell As Range
With ws.UsedRange
Set LastCell = .Cells(.Rows.Count, .Columns.Count)
Debug.Print "UsedRange: " & .Address(0, 0)
Debug.Print "LastCell: " & LastCell.Address(0, 0)
End With
' Reference the header cell.
Dim HeaderCell As Range
Set HeaderCell = ws.Cells.Find(sHeader, LastCell, xlFormulas, xlWhole)
If HeaderCell Is Nothing Then Exit Sub ' header not found
Debug.Print "HeaderCell: " & HeaderCell.Address(0, 0)
' Calculate the first column number.
Dim FirstColumn As Long: FirstColumn = HeaderCell.Column + 1
Debug.Print "FirstColumn: " & FirstColumn
' Calculate the last column number.
Dim LastColumn As Long: LastColumn = _
ws.Cells(HeaderCell.Row, ws.Columns.Count).End(xlToLeft).Column
If LastColumn < FirstColumn Then Exit Sub ' no data to the right of header
Debug.Print "LastColumn: " & LastColumn
' Reference the column range below the header cell
' to search for the property.
Dim sDataColumnRange As Range ' below the header
Set sDataColumnRange _
= HeaderCell.Resize(LastCell.Row - HeaderCell.Row).Offset(1)
Debug.Print "sDataColumnRange: " & sDataColumnRange.Address(0, 0); ""
' Reference the property cell.
Dim sPropertyCell As Range
With sDataColumnRange
Set sPropertyCell _
= .Find(sProperty, .Cells(.Rows.Count), xlFormulas, xlWhole)
If sPropertyCell Is Nothing Then Exit Sub ' property not found
Debug.Print "sPropertyCell: " & sPropertyCell.Address(0, 0)
End With
' Reference the property (values) row range (first to last column).
Dim PropertyRowRange As Range
Set PropertyRowRange = ws.Range(ws.Cells(sPropertyCell.Row, FirstColumn), _
ws.Cells(sPropertyCell.Row, LastColumn))
Debug.Print "PropertyRowRange: " & PropertyRowRange.Address(0, 0)
Debug.Print "PropertyRowRange Values" & vbLf & Join(Application.Transpose( _
Application.Transpose(PropertyRowRange.Value)), ", ")
' Populate the property values array.
Dim PropertyValuesArray As Variant
PropertyValuesArray = Application.Transpose(Evaluate("Row(320:420)"))
Debug.Print "PropertyValuesArray Values"
Debug.Print Join(PropertyValuesArray, ", ")
' Return the result whether all values of the property row range
' are found in the property values array.
If IsRowInArr(PropertyValuesArray, PropertyRowRange) Then
MsgBox "All matching.", vbInformation
Debug.Print "All matching."
Else
MsgBox "Not all matching.", vbCritical
Debug.Print "Not all matching."
End If
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Returns a boolean indicating whether a 1D array ('InArr')
' contains all values in a row ('RowIndex')
' of a range ('IsRange').
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function IsRowInArr( _
ByVal InArr As Variant, _
ByVal IsRange As Range, _
Optional ByVal RowIndex As Long = 1) _
As Boolean
Const ProcName As String = "IsRowInArr"
On Error GoTo ClearError
With IsRange.Rows(RowIndex)
Dim cCount As Long: cCount = .Columns.Count
If cCount = 1 Then
IsRowInArr = IsNumeric(Application.Match(.Value, InArr, 0))
Else
Dim IsRow As Variant: IsRow = .Value
IsRowInArr = Application.Count(Application.Match( _
IsRow, InArr, 0)) = cCount
End If
End With
ProcExit:
Exit Function
ClearError:
Debug.Print "'" & ProcName & "' Run-time error '" _
& Err.Number & "':" & vbLf & " " & Err.Description
Resume ProcExit
End Function
Initial Answer
The function will return true if all the elements of an array (IsArr) are found in another array (InArr).
Option Explicit
Sub IsArrayInArrayTEST()
Dim InArr As Variant: InArr = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
Dim IsArr As Variant
IsArr = Array(1)
Debug.Print IsArrayInArray(IsArr, InArr) ' True
IsArr = Array(1, 5, 11)
Debug.Print IsArrayInArray(IsArr, InArr) ' False
End Sub
Function IsArrayInArray( _
ByVal IsArr As Variant, _
ByVal InArr As Variant) _
As Boolean
Dim IsCount As Long: IsCount = UBound(IsArr) - LBound(IsArr) + 1
Dim rArr As Variant: rArr = Application.Match(IsArr, InArr, 0)
Dim rCount As Long: rCount = Application.Count(rArr)
'Debug.Print rCount, IsCount
If rCount = IsCount Then
IsArrayInArray = True
End If
End Function

List all unique values based on criterias

I need to list all values that have a specific criteria in other columns as shown
I have the following:
Sub arytest()
Dim ary()
Dim note2()
Dim lastrow As Long
Dim i As Long
Dim k As Long
Dim eleAry, x
'Number of rows in my data file
lastrow = Sheet2.Cells(Sheet2.Rows.Count, "A").End(xlUp).Row
'The maximum length of my array
ReDim ary(1 To lastrow)
k = 1
For i = 1 To lastrow
If Cells(i, 2) Like "*Note 2*" _ ' Criterias that needs to be fullfilled
And Cells(i, 1) Like "Actuals" _
And Cells(i, 4) Like "Digitale Brugere" Then
ary(k) = Cells(i, 3)
k = k + 1
End If
Next i
End Sub
This code lists all values I need. However some of them are present multiple times. How can I remove duplicates?
Here is another way, so you won't need to remove duplicates later, using Scripting Dictionary (you need to check the Microsoft Scripting Runtime on the libraries for this to work)
Sub arytest()
Dim ary()
Dim note2() 'unsued
Dim lastrow As Long
Dim i As Long
Dim k As Long
Dim eleAry, x 'unused
Dim DictDuplicates As Scripting.Dictionary
Set DictDuplicates = New Scripting.Dictionary
'Number of rows in my data file
lastrow = Sheet2.Cells(Sheet2.Rows.Count, "A").End(xlUp).Row
'The maximum length of my array
ReDim ary(1 To lastrow)
k = 1
For i = 1 To lastrow
' Criterias that needs to be fullfilled
If Cells(i, 2) Like "*Note 2*" _
And Cells(i, 1) Like "Actuals" _
And Cells(i, 4) Like "Digitale Brugere" Then
If Not DictDuplicates.Exists(Cells(i, 3).Value) Then 'check if the value is already on the array
ary(k) = Cells(i, 3)
DictDuplicates.Add Cells(i, 3).Value, i 'if it does not exists, add it to the dictionary
End If
k = k + 1
End If
Next i
End Sub
I've also seen some variables unused on your code, or at least what you posted.
PS: when using the Likeoperator you should use the wildcards* or ?, without them is the same as if you were using the = operator.

Increment different counters depending on array index value

I have a vast list of data in a worksheet (called MainDump). I have a procedure set up to assess this list and return certain values using the following setup:
Dim ws1 As Worksheet
Set ws1 = Worksheets("DashBoard")
Dim ws2 As Worksheet
Set ws2 = Worksheets("MainDump")
Dim cntr As Long
On Error GoTo ErrorHandler 'Got A lot of divide by zero errors if searchstring wasn't found
With Application.WorksheetFunction
ws1.Range("O4").Value = .CountIf(ws2.Range("E:E"), "*" & "CEOD" & "*")
ws1.Range("L4").Value = .CountIfs(ws2.Range("E:E"), "*" & "CEOD" & "*", ws2.Range("A:A"), "Yes") / ws1.Range("O4").Value
ws1.Range("M4").Value = .CountIfs(ws2.Range("E:E"), "*" & "CEOD" & "*", ws2.Range("B:B"), "Yes") / ws1.Range("O4").Value
ws1.Range("N4").Value = .CountIfs(ws2.Range("E:E"), "*" & "CEOD" & "*", ws2.Range("C:C"), "SA Present, WBDA Present") / ws1.Range("O4").Value
End With
cntr = cntr + 1
'^This proces is then copied and thus repeated a total of 76 times, as I want to check
'for 76 different values in ws2.Range("E:E"), resulting in a massive code
ErrorHandler:
If Err.Number = 6 Then
If ws1.Range("O" & cntr).Value = 0 Then
ws1.Range("L" & cntr).Value = "div. by zero"
ws1.Range("M" & cntr).Value = "div. by zero"
ws1.Range("N" & cntr).Value = "div. by zero"
End If
End If
Resume Next
I wrote this when I was a lot less experienced in VBA. Needless to say this code takes a lot of time to complete (Maindump counts about 98000 rows).
So I wanted to try do this work via an array.
My approach would be to define a counter for each string I want to check in the array indexes and then looping through the array and increment the corresponding counters when a string is found in the Array. My question is if there is a way to write that loop in the following form:
Dim LastRow1 As long
Dim DataArray() As Variant
Dim SearchString1, SearchString2, .... SearchString76 As String
Dim SearchString1Cntr, SearchString2Cntr, .... SearchString76Cntr As long
With ws2
LastRow1 = .Cells.Find(What:="*", After:=.Range("A1"), LookAt:=xlPart, LookIn:=xlFormulas, _
SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False).Row 'Gets the total row amount in the sheet
DataArray = .Range("A3:E" & LastRow1) 'puts selected range in Array
End With
For LastRow1 = Lbound(DataArray, 1) to Ubound(DataArray, 1)
'Start a For Each loop to check for all 76 strings
If Instr(1, DataArray(LastRow1, 5), SearchString > 0 Then 'SearchString is found so then
SearchStringCntr1 = SearchStringcntr1 + 1
'Where SearchStrinCntr1 is the counter related to the string checked for in the loop,
'so it switches when the SearchString changes
End If
'Next SearchString to check
Next LastRow1
So I want to try and use a flexible If statement in a For Next loop which checks the Array index for each SearchString and then increments the corresponding SearchStringCntr if the SearchString is found in the index, before looping to the next index. Is this possible? I would like to prevent making 76 different If/ElseIf statements for each SearchString + StringCntr and then use a counter to loop through them every time the code loops through the For LastRow1 / Next LastRow1 loop. Would love to hear your input.
Maybe this will help (might need some adjustments).
Create named range "Strings" somewhere in your workbook where you'll store all your strings that you're looking for
Option Explicit
Sub StringsCompare()
Dim LastRow1 As Long
Dim DataArray() As Variant, StringArray() As Variant
Dim Ws2 As Worksheet
Dim CompareStringsNo As Long, StringCounter As Long
Dim i As Long, j As Long
Dim aCell As Range
Dim SourceStr As String, SearchStr As String
Set Ws2 = ThisWorkbook.Sheets("Sheet1")
StringCounter = 1
With Ws2
'fill array with your strings to compare
CompareStringsNo = .Range("Strings").Rows.Count
ReDim StringArray(1 To CompareStringsNo, 1 To 2)
For Each aCell In .Range("Strings")
StringArray(StringCounter, 1) = aCell.Value
StringCounter = StringCounter + 1
Next aCell
'fill data array
LastRow1 = .Cells.Find(What:="*", After:=.Range("A1"), LookAt:=xlPart, LookIn:=xlFormulas, _
SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False).Row 'Gets the total row amount in the sheet
DataArray = .Range("A1:E" & LastRow1)
End With
'search data array
For i = LBound(DataArray, 1) To UBound(DataArray, 1)
SourceStr = DataArray(i, 5)
'search array with your strings
For j = LBound(StringArray) To UBound(StringArray)
SearchStr = StringArray(j, 1)
If InStr(1, SourceStr, SearchStr) > 0 Then
'if match is found increase counter in array
StringArray(j, 2) = StringArray(j, 2) + 1
'you can add exit for here if you want only first match
End If
Next j
Next i
For i = LBound(StringArray) To UBound(StringArray)
Debug.Print StringArray(i, 1) & " - " & StringArray(i, 2)
Next i
End Sub
I think the main task is being over-complicated.
To check how many times a string occurs within an array you could use a function like this:
Function OccurWithinArray(theArray As Variant, stringToCount As String) As Long
Dim strArr As String
strArr = Join(theArray, " ")
OccurWithinArray = (Len(strArr) - Len(Replace(strArr, stringToCount, _
vbNullString, , , vbTextCompare))) / Len(stringToCount)
End Function
...and a demonstration:
Sub Demo()
Dim test(1 To 3) As String
test(1) = "I work at the Dog Pound."
test(2) = "I eat dogfish regularly."
test(3) = "Steroidogenesis is a thing."
Debug.Print OccurWithinArray(test, "dog")
End Sub
How it works:
Join joins all the elements of the array into one big string.
Len returns the length of the text.
Replace temporarily replaces the removes all occurrences of the search term.
Len returns the "modified" length of the text.
The difference between the two Len's, divided by the length of the string being searched for, is the number aof occurrences of the string within the entire array.
This returns 3 since the search is case-insensitive.
To make the search case-sensitive, remove the word vbTextCompare (in which case this example would return 2.)

Trouble with Arrays in vba

Thank you for all of the help. I have successfully populated and reviewed the contents of my array. Now I am having trouble calling the specific instances (string values) within the array in a function I wrote to compare cells in the sheet to the values in the array....
I am getting the "subscript out of range" inside of my function in my strcomp(). I have checked and the right value is being passed via vCompare.
Arrays are so finicky!
Here is the updated code:
Sub searchTrucks()
Dim lastRow As Long
Dim EndRow As Long
Dim showAll As Boolean
Dim BeginRow As Long
Dim RowCnt As Long
Dim chckTech As Long
Dim chckReg As Long
Dim chckSite As Long
Dim chckUnum As Long
Dim chckType As Long
Dim chckAge As Long
Dim chckDt As Long
Dim chckCap As Long
Dim i As Integer
Dim aRan As Range
Dim bRan As Range
Dim cRan As Range
Dim rrRan As Range
Dim rmRan As Range
Dim marray() As Variant
marray = WorksheetFunction.Transpose(Worksheets("Calculations").Range("F2:K2"))
Dim vCompare As String
Dim x As Long
Dim y As Long
y = 2
x = 1
i = 1
lastRow = Application.CountA(Sheets("Trucks").Range("C:C"))
BeginRow = 6
EndRow = lastRow + 4
chckSite = 3
chckUnum = 4
chckType = 5
chckAge = 7
chckDt = 10
chckCap = 11
Debug.Print lastRow
For i = 1 To 8
If IsEmpty(Sheets("Trucks").Cells(2, i).Value) Then
showAll = True
Else
showAll = False
Exit For
End If
Next i
Debug.Print showAll
If showAll = False Then
For RowCnt = BeginRow To EndRow
If Not IsEmpty(Sheets("Trucks").Cells(2, 3).Value) And IsEmpty(Sheets("Trucks").Cells(2, 4).Value) Then
For y = 2 To 6
If Sheets("Trucks").Cells(2, 3).Value = Sheets("Calculations").Cells(y, 5).Value Then
vCompare = Sheets("Trucks").Cells(RowCnt, chckSite).Value
If IsInArray(vCompare, marray) = -1 Then
Cells(RowCnt, chckSite).EntireRow.Hidden = True
End If
End If
Next
Stop
End If
If Not IsEmpty(Sheets("Trucks").Cells(2, 4).Value) And Sheets("Trucks").Cells(RowCnt, chckSite).Value <> Sheets("Trucks").Cells(2, 4).Value Then
Cells(RowCnt, chckSite).EntireRow.Hidden = True
ElseIf Not IsEmpty(Sheets("Trucks").Cells(2, 5).Value) And Sheets("Trucks").Cells(RowCnt, chckUnum).Value <> Sheets("Trucks").Cells(2, 5).Value Then
Cells(RowCnt, chckUnum).EntireRow.Hidden = True
ElseIf Not IsEmpty(Sheets("Trucks").Cells(2, 6).Value) And Sheets("Trucks").Cells(RowCnt, chckType).Value <> Sheets("Trucks").Cells(2, 6).Value Then
Cells(RowCnt, chckType).EntireRow.Hidden = True
ElseIf Not IsEmpty(Sheets("Trucks").Cells(2, 7).Value) And Sheets("Trucks").Cells(RowCnt, chckAge).Value < Sheets("Trucks").Cells(2, 7).Value Then
Cells(RowCnt, chckAge).EntireRow.Hidden = True
ElseIf Not IsEmpty(Sheets("Trucks").Cells(2, 9).Value) And Sheets("Trucks").Cells(RowCnt, chckDt).Value < Sheets("Trucks").Cells(2, 9).Value Then
Cells(RowCnt, chckDt).EntireRow.Hidden = True
ElseIf Not IsEmpty(Sheets("Trucks").Cells(2, 10).Value) And Sheets("Trucks").Cells(RowCnt, chckCap).Value < Sheets("Trucks").Cells(2, 10).Value Then
Cells(RowCnt, chckCap).EntireRow.Hidden = True
End If
Next RowCnt
Else
Sheets("Trucks").Cells.EntireRow.Hidden = False
End If
Here is my function code:
Function IsInArray(stringToBeFound As String, arr As Variant) As Long
Dim i As Long
' default return value if value not found in array
IsInArray = -1
Debug.Print stringToBeFound
For i = LBound(arr) To UBound(arr)
If StrComp(stringToBeFound, arr(i), vbTextCompare) = 0 Then
IsInArray = i
Exit For
End If
Next i
End Function
To populate your arrays you can do this
Dim aArray As Variant
aArray = WorksheetFunction.Transpose(Worksheets("Calculations").Range("F2:K2"))
And similarly for all the rest of your arrays.
You cannot use debug.print on arrays. Instead, in your VBA editor right-click on the variable name (aArray) and select "Add watch". Your variable will appear in the "Watches" window. Now add a break-point just after you (correctly) populate aArray in the code and run your code. It will stop at the break-point and you can now go into the "Watches" window and expand the aArray variable. You will see the contents of the array here.
Regarding the use of the Array function, see here - a comma delimited list of items is required. It is often used to do quick-and-dirty creation of variant arrays, often for static data consisting of small lists. For instance, things like Array("Jan", "Feb", "Mar",...,"Dec")... stuff like that.
You generally do not need to call this constructor explicitly when using arrays. For simple non-Variant data types an array of type X is defined like so:
dim an_X_array(10) as X
This defines an_X_array to be an array of 10 items that each have type X
Compare this to a simple variable defined to be of type X
dim an_X as X
With regards to your second problem - it is being caused by the array you create from your range (worksheet data) being constructed as a 2-dimensional array. You can either work with 2-dimensional arrays, and change your formulas, or use the below helper function to create a 1-dimensional array from your worksheet data. Here is the function to create a proper 1-dimensional array from any worksheet range (just copy-paste it somewhere in your code module):
Public Function RngToArray(ByRef InputRange As Range) As Variant
Dim A As Variant
Dim rr As Range
Dim i As Long
ReDim A(InputRange.Cells.Count)
i = LBound(A)
For Each rr In InputRange
A(i) = rr.Value
i = i + 1
Next
ReDim Preserve A(i - 1)
RngToArray = A
End Function
And for your example you then need to replace just one line of your code:
change
marray = WorksheetFunction.Transpose(Worksheets("Calculations").Range("F2:K2"))
to
marray = RngToArray(Worksheets("Calculations").Range("F2:K2"))
the way you populate your array , you will get a 2 dimensional array, so i modified your source code to test if your value is in the array :
Function IsInArray( Byval stringToBeFound As String, Byref arr As Variant) As Long
Dim i As Long 'i is the columns variable
Dim J& 'j is the rows variable
' default return value if value not found in array
IsInArray = -1
Debug.Print stringToBeFound
For i = LBound(arr,2) To UBound(arr,2) 'the ,2 is to say the 2nd dimension (same order of dimensions as if you'd use the cells function)
For j = LBound(arr,1) To UBound(arr,1)
If stringToBeFound = arr(j,i) Then 'simple test of strings
IsInArray = i 'will give the column as answer
Exit Function 'Exit For
End If
Next i
End Function

Creating an array variable with a variable number of elements

I want to define an array variable to have a variable number of elements depending on the m number of results returned from a search. I get an error "Constant Expression Required" on:
Dim cmodels(0 To m) As String
Here is my complete code
Dim foundRange As Range
Dim rangeToSearch As Range
Set rangeToSearch = Selection
Set foundRange = rangeToSearch.Find(What:="Lights", After:=ActiveCell,
LookIn:=xlValues, LookAt:= _
xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False _
, SearchFormat:=False) 'First Occurrence
m = WorksheetFunction.CountIf(Selection, "Lights")
Dim secondAddress As String
If (Not foundRange Is Nothing) Then
Dim count As Integer: count = 0
Dim targetOccurrence As Integer: targetOccurrence = 2
Dim found As Boolean
z = 1
Dim cmodels(0 To m) As String
Do Until z = m
z = z + 1
foundRange.Activate
Set foundRange = rangeToSearch.FindNext(foundRange)
If Not foundRange.Next Is Nothing Then
z(m) = ActiveCell(Offset(0, 2))
End If
Loop
End If
End Sub
See the following code comments:
Sub redimVsRedimPreserve()
'I generally declare arrays I know I will resize
'without a fixed size initially..
Dim cmodels() As String
Dim m As Integer
m = 3
'this will wipe out all data in the array
ReDim cmodels(0 To m) As String
'you can also use this if you want to save all information in the variable
cmodels(2) = "test"
ReDim Preserve cmodels(0 To m) As String
'this will still keep "test"
Debug.Print "With redim preserve, the value is: " & cmodels(2)
'using just 'redim'
ReDim cmodels(0 To m) As String
Debug.Print "with just redim, the value is: " & cmodels(2)
End Sub
Also note that using Redim Preserve frequently (such as a loop) can be an operation which takes some time.
Dim cmodels() As String
'...
ReDim cmodels(0 to m)

Resources