Search a range using values from an array - arrays

I'm trying to write a small macro to search a range of values (provided by an array full of user input) and, for the most part, return their current row. This range is a printable toolsheet of which I only need to print pages that I make changes too, therefore I am attempting to simplify my job by inputting the tools that have been updated, and having the macro tell me what pages to print.
I tried to make that as understandable as possibly, but let me know if clarification is needed.
The problem arises when I try to search the sheet using 'Application.WorksheetFunction'
Sub FunWithArrays()
Dim ToolNumber()
Dim i As Integer
i = 1
ReDim ToolNumber(1)
Do
ToolNumber(i) = InputBox("Please type the name of the tool with proper capitalization.", "Tool Number")
ReDim Preserve ToolNumber(UBound(ToolNumber) + 1)
i = i + 1
Loop Until ToolNumber(i - 1) = "Done"
MsgBox "Thank you for inputting the tool numbers.", vbOKOnly, "Input Complete"
Dim j As Integer
Dim ToolNoRow As Range
Dim PageNo As Double
For j = 1 To (i - 2)
ToolNoRow = Application.WorksheetFunction.Range("A:A").Text.Find(what:=ToolNumber(j), LookIn:=xlValues, lookat:=xlWhole)
PageNo = Application.WorksheetFunction.RoundUp((ToolNoRow / 1), 0)
MsgBox "Please print page " & PageNo
Next
End Sub
Any and all help is appreciated! Thank you!

I am not sure that I fully understand how you macro works, since it looks like you want to return row numbers but you talk about returning page numbers.
However, if you want to return the range of a cell in which a given input is found (since you have declared ToolNoRow As Range) you would do this by:
Set ToolNoRow = Worksheets("Sheet1").Range("A:A").Text.Find(what:=ToolNumber(j), LookIn:=xlValues, lookat:=xlWhole)
Note that you would have to state in what sheet you want to perform the search.
If you instead want to return the row in which this input is found, you could declare ToolNoRow as Long and then use:
ToolNoRow = Worksheets("Sheet1").Range("A:A").Text.Find(what:=ToolNumber(j), LookIn:=xlValues, lookat:=xlWhole).Row
You should probably include some error handling in your code, because Excel would return an error message whenever a search item is not found.

Try this
You may need to mod the logic after you get the cell address
Dim ToolNumber()
Dim i As Integer
i = 1
ReDim ToolNumber(1)
Do
ToolNumber(i) = InputBox("Please type the name of the tool with proper capitalization.", "Tool Number")
ReDim Preserve ToolNumber(UBound(ToolNumber) + 1)
i = i + 1
Loop Until ToolNumber(i - 1) = "Done"
MsgBox "Thank you for inputting the tool numbers.", vbOKOnly, "Input Complete"
Dim j As Integer
Dim ToolNoRow As Range
Dim PageNo As Double
For j = 1 To (i - 2)
With Range("A:A")
Set ToolNoCell = Find(what:=ToolNumber(j), LookIn:=xlValues, lookat:=xlWhole)
If Not c Is Nothing Then
firstAddress = c.Address
Do
c.Value = 5
Set c = .FindNext(c)
Loop While Not c Is Nothing And c.Address <> firstAddress
End If
End With
'Do whatever Here
PageNo = Application.WorksheetFunction.RoundUp((ToolNoRow / 1), 0)
MsgBox "Please print page " & PageNo
Next

Related

Application-defined or Object-defined Error - Resize Ubound, Application.Transpose

I am having an issue with a small code we made for a specific task. In short, the task is to take an input of two columns; (A) containing rows with productsnumbers (and duplicates) and (B) containing a corresponding value for that particular productnumber.
Instead of having 100.000 of rows, we want to have one UNIQUE productnumber in column A and the corresponding (concatenated) values in Column B. This was achieved.
I found most of the code here on stack and changed it a bit. Would love to link, but can't remember where exactly I got it - sorry!
Now, we have a lot of rows and hence the original code ran into an issue, because the loop variable (i) was dimmed as an Integer.
TO FIX THAT i quickly changed it to type Long. However, this presents me with another issue: "Run-time error '1004': Application-defined or object-defined error"
Debugging tells me it is the commented part below, that presents an issue, but I am unable to fix it.
Any help is greatly appreciated. Thank you so much in advance!!
Option Explicit
Sub groupConcat()
Dim dc As Object
Dim inputArray As Variant
Dim i As Long
Dim lastRow As Long
Getting lastRow
lastRow = Range("A" & Rows.Count).End(xlUp).Row
Formatting E to text
Range("E1:E20000").NumberFormat = "#"
Clear worksheet before any further work is done
Worksheets("Sheet1").Range("D2:E20000").ClearContents
Set dc = CreateObject("Scripting.Dictionary")
inputArray = WorksheetFunction.Transpose(Sheets(1).Range("A2:B" & lastRow).Value)
'-- assuming you only have two columns - otherwise you need two loops
For i = LBound(inputArray, 2) To UBound(inputArray, 2)
If Not dc.Exists(inputArray(1, i)) Then
dc.Add inputArray(1, i), inputArray(2, i)
Else
dc.Item(inputArray(1, i)) = dc.Item(inputArray(1, i)) _
& "," & inputArray(2, i)
End If
Next i
'--output into sheet
Sheets(1).Range("D2").Resize(UBound(dc.keys) + 1) = _
Application.Transpose(dc.keys)
ISSUE BELOW
Sheets(1).Range("E2").Resize(UBound(dc.items) + 1) = _
Application.Transpose(dc.items)
Set dc = Nothing
End Sub
maybe the double transpose. Try this version and see if it works for you:
Sub DictMatch()
Dim arr, j As Long, dict As Object
arr = Sheet1.Range("A1").CurrentRegion.Value2 'load source
Sheet1.Range("A1").CurrentRegion.ClearContents
Set dict = CreateObject("Scripting.Dictionary") 'create dictionary lateB
With dict 'used because I'm to lazy to retype dict everywhere :)
For j = 1 To UBound(arr) 'traverse source
If Not .Exists(arr(j, 1)) Then 'set key if I don't have it yet in dict
.Add Key:=arr(j, 1), Item:=arr(j, 2)
Else
dict(arr(j, 1)) = dict(arr(j, 1)) & "," & arr(j, 2)
End If
Debug.Print arr(j, 1), dict(arr(j, 1))
Next j
End With
With Sheet1 'dump target array to sheet
.Cells(1, 1).Resize(dict.Count, 1).Value2 = Application.Transpose(dict.keys)
.Cells(1, 2).Resize(dict.Count, 1).Value2 = Application.Transpose(dict.Items)
End With
End Sub

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.)

array references in a vba loop?

OK... second attempt at posting this. Trying to make my question make sense please be patient with me, I am new at all of this.
The code below words PERFECTLY. It reads from the Range in column A and give me a string of all the cells where the searched numbers occur.
My only issue is its obviously not condensed at all. I have tried loops and arrays for the references but i can't seem to get it work. i would prefer something along the lines of reference(1-10) in stead of ref1, ref2, ref3. i had them all ref(i) with a loop around the whole macro but i ended up getting no results and an endless loop. any help to make this more streamlined would be appreciated. i have the full code if that will help anyone. I only put three iterations of the code it simply continues on with more references. up to 9
Option Explicit
Sub FindAircraftHourly()
Dim Findarray() As Integer 'the array to put numbers in
Dim count1, count2, count3, count4, count5, count6, count7, count8, count9 As Integer 'this will count the number of records you will need for your array
Dim n1, n2, n3, n4, n5, n6, n7, n8, n9 As Integer 'this will be what gets you through your For loops
Dim Searchvalue1, Searchvalue2, Searchvalue3, Searchvalue4, Searchvalue5, Searchvalue6, Searchvalue7, Searchvalue8, Searchvalue9 As Integer 'this is the number to look for
Dim Foundstring1, Foundstring2, foundstring3, foundstring4, foundstring5, foundstring6, foundstring7, Foundstring8, Foundstring9 As String 'this will build where the numbers are found
Dim k1 As Integer
Dim data As Worksheet
Set data = ThisWorkbook.Sheets("data")
If Cells(1, 3) <> "" Then 'test to make sure it has something to look for
Searchvalue1 = Cells(1, 3) * 1 'E18 is the search value for the function this converts it to number and not text
Else
MsgBox "No input found!", vbCritical 'if blank, give a warning and quit
GoTo the_end
End If
k1 = data.Range("A5000").End(xlUp).Row
count1 = 0 'always initialize your variables
For n1 = 1 To k1 'count through all the rows to find the end of the list
If Cells(n1, 1) <> "" Then 'is the cell blank or not?
count1 = count1 + 1 'if not blank, then increase the count
Else
Exit For 'if it's blank, stop looking and counting
End If
Next n1
ReDim Findarray1(0 To count1 - 1) As Integer 'array indexes start at 0, so subtract 1 to get the right number of elements
For n1 = 0 To UBound(Findarray1) 'go from the first element to the last of the array
Findarray1(n1) = Cells(n1 + 1, 1) 'load the array change the last number in the cells box to change where to start looking
Next n1
For n1 = 0 To UBound(Findarray1)
If Findarray1(n1) = Searchvalue1 Then
If Foundstring1 = "" Then 'if this is the first time found, create the string
Foundstring1 = n1 + 1
Else
Foundstring1 = Foundstring1 & ", " & n1 + 1 'if this is the second time the number is found, add a comma and continue to build the string.
End If
End If
Next n1
If Foundstring1 = "" Then
MsgBox "Not found", vbCritical 'msgbox nothing was found
Else
Cells(1, 4) = Foundstring1 'output the string to a certain cell
End If
'-----------------------------------------------------------------------
If Cells(2, 3) <> "" Then 'test to make sure it has something to look for
Searchvalue2 = Cells(2, 3) * 1 'E18 is the search value for the function this converts it to number and not text
Else
MsgBox "No input found!", vbCritical 'if blank, give a warning and quit
GoTo the_end
End If
k1 = data.Range("A5000").End(xlUp).Row
count2 = 0 'always initialize your variables
For n2 = 1 To k1 'count through all the rows to find the end of the list
If Cells(n2, 1) <> "" Then 'is the cell blank or not?
count2 = count2 + 1 'if not blank, then increase the count
Else
Exit For 'if it's blank, stop looking and counting
End If
Next n2
ReDim FindArray2(0 To count2 - 1) As Integer 'array indexes start at 0, so subtract 1 to get the right number of elements
For n2 = 0 To UBound(FindArray2) 'go from the first element to the last of the array
FindArray2(n2) = Cells(n2 + 1, 1) 'load the array change the last number in the cells box to change where to start looking
Next n2
For n2 = 0 To UBound(FindArray2)
If FindArray2(n2) = Searchvalue2 Then
If Foundstring2 = "" Then 'if this is the first time found, create the string
Foundstring2 = n2 + 1
Else
Foundstring2 = Foundstring2 & ", " & n2 + 1 'if this is the second time the number is found, add a comma and continue to build the string.
End If
End If
Next n2
If Foundstring2 = "" Then
MsgBox "Not found", vbCritical 'msgbox nothing was found
Else
Cells(2, 4) = Foundstring2 'output the string to a certain cell
End If
'-----------------------------------------------------------
If Cells(3, 3) <> "" Then 'test to make sure it has something to look for
Searchvalue3 = Cells(3, 3) * 1 'E18 is the search value for the function this converts it to number and not text
Else
MsgBox "No input found!", vbCritical 'if blank, give a warning and quit
GoTo the_end
End If
k1 = data.Range("A5000").End(xlUp).Row
count3 = 0 'always initialize your variables
For n3 = 1 To k1 'count through all the rows to find the end of the list
If Cells(n3, 1) <> "" Then 'is the cell blank or not?
count3 = count3 + 1 'if not blank, then increase the count
Else
Exit For 'if it's blank, stop looking and counting
End If
Next n3
ReDim FindArray3(0 To count3 - 1) As Integer 'array indexes start at 0, so subtract 1 to get the right number of elements
For n3 = 0 To UBound(FindArray3) 'go from the first element to the last of the array
FindArray3(n3) = Cells(n3 + 1, 1) 'load the array change the last number in the cells box to change where to start looking
Next n3
For n3 = 0 To UBound(FindArray3)
If FindArray3(n3) = Searchvalue3 Then
If foundstring3 = "" Then 'if this is the first time found, create the string
foundstring3 = n3 + 1
Else
foundstring3 = foundstring3 & ", " & n3 + 1 'if this is the second time the number is found, add a comma and continue to build the string.
End If
End If
Next n3
If foundstring3 = "" Then
MsgBox "Not found", vbCritical 'msgbox nothing was found
Else
Cells(3, 4) = foundstring3 'output the string to a certain cell
End If
the_end: 'end marker
End Sub
I'm not sure what your data looks like, but I would suggest a few things:
'finds the absolute last row with data in it // ignores empty cells
k1 = data.UsedRange.Rows.Count
count1 = 0
For n1 = 1 To k1
'here's a built-in function to help you check empty cells.
'if you're going to reference ranges, then you need to define on which worksheet
'you're referencing the ranges from. if you work with multiple worksheets, you
'can't simply use Cells(x,y); you need to use worksheet.Cells(x,y).
'If you want to access a cell's value, then you use the .Value property.
If Not IsEmpty(data.Cells(n1, 1).Value) Then
count1 = count1 + 1
Else
Exit For
End If
Next n1
I highly suggest using Collections instead of arrays because, for me, they're far easier to deal-with than arrays. They also start their indices at 1, so if you have a collection of 10 items, you count 1 through 10 instead of 0 through 9.
Defining and setting Collections:
Dim FindArray As New Collection
Or
Dim FindArray As Collection
Set FindArray = New Collection
Iterating over a collection:
Dim v As Variant
Dim sample As Double
For Each v In FindArray
'i personally like to recast all variant types to
'the intended data type
sample = v
'do your thing here
Next
Or
For i = 0 To FindArray.Count
'do your other thing here
Next
Here's my attempt at making your code cleaner; hope it helps!
PS: All my castings are based on assumptions, so change them to whatever type you were intending.
Main:
Dim wb As Workbook
Dim data As Worksheet
Dim n As Long
Dim SearchValue As Double
Dim Found As String
Dim output As New Collection
Dim FindArray As Collection
Dim count As Long
Dim k As Long
Dim i As Long
Dim j As Long
Set wb = Excel.Application.ThisWorkbook
Set data = wb.Worksheets("data")
k = data.UsedRange.Rows.Count
'find the last row before an empty record appears
For n = 1 To k
If Not IsEmpty(data.Cells(n, 1).Value) Then
count = n
ElseIf IsEmpty(data.Cells(n ,1).Value) Then
Exit For
End If
Next
'do the thing 9 times
For n = 1 To 9
If Not IsEmpty(data.Cells(n, 3).Value) Then
'cast the cell value to double and assign it to searchvalue
SearchValue = CDbl(data.Cells(n, 3).Value)
'i prefer to be extremely specific, but that's just me
Elseif IsEmpty(data.Cells(n, 3).Value) Then
MsgBox "No input found!", vbCritical
GoTo the_end
End If
'reset findarray to an empty collection
Set FindArray = New Collection
For i = 1 To count
'load your collection with the sample values casted to doubles
FindArray.Add CDbl(data.Cells(i, 1).Value)
Next
j = 1
Found = ""
For i = 1 To FindArray.Count
If FindArray(i) = SearchValue Then
If j = 1 Then
Found = i
ElseIf j > 1 Then
'im not sure what you're trying to accomplish with this line,
'so im just going to leave it as is and adjust it for my solution
'so it gives you the same output
Found = n & ", " & i
End If
j = j + 1
End If
Next
If Found = "" Then
MsgBox "Not found", vbCritical
Else
output.Add Found
End If
'i like to always just set the collection to nothing before a new iteration
Set FindArray = Nothing
Next
'dump all results in column 4
For i = 1 To output.Count
data.Cells(i, 4).Value = output(i)
Next
'garbage collection
Set FindArray = Nothing
Set output = Nothing
Set wb = Nothing
Set data = Nothing
the_end:
Exit Sub
I'm not entirely sure if this attempt at a solution will work for you, but I hope it's helpful in any way. Good luck!
Col A populated with values, Col C populated with search values to be found in Col A, Col D is where the row numbers of each value in Col C can be found.
The number of values in Col A and Col C are essentially limited only by the number of rows in your spreadsheet with no changes required to the code.
If you have not added a Dictionary reference, click on [Tools] at the top of the screen, click on [References...], scroll way down until you find [Microsoft Scripting Runtime], click the check mark next to that, then click [OK].
Sub FindAircraftHourly()
Dim dnySource As New Scripting.Dictionary
Dim strCellValue As String
Dim i0 As Long
With ActiveSheet
For i0 = 2 To .Rows.Count 'This starts at row 2 and goes to the end of the list. I'm assuming row 1 has a heading of some sort.
If Not IsEmpty(.Cells(i0, 1)) Then 'If the cell in col A of that row has a value, add that value to the dictionary as the key and the row number(s) as the items(s).
strCellValue = .Cells(i0, 1).Value
dnySource(strCellValue) = dnySource(strCellValue) & i0 & ", "
Else
Exit For 'Once you hit an empty cell, stop building the dictionary.
End If
Next i0
For i0 = 2 To .Rows.Count
If Not IsEmpty(.Cells(i0, 3)) Then 'If the cell in col C has a value then look through the dictionary to see if you have a list of row numbers to display.
strCellValue = .Cells(i0, 3).Value
If dnySource.Exists(strCellValue) Then 'If there is a list of row numbers for that value, display them in col D.
.Cells(i0, 4).Value = Left$(dnySource(strCellValue), Len(dnySource(strCellValue)) - 2) 'The - 2 here chops off the extra ", " at the end
Else 'Otherwise, indicate that the value in col C doesn't exist in col A.
.Cells(i0, 4).Value = "Value Not Found"
End If
Else
Exit For
End If
Next i0
End With
End Sub
Here's my attempt to solve your problem.
For questions just ask.
Option Explicit
Sub FindAircraftHourly()
Dim data As Worksheet
Dim searchrange As Range
Dim cell As Range
Dim findarray() As String
Dim searcharray() As Integer
Dim i As Integer
Set data = ThisWorkbook.Worksheets("data") 'the sheet your working on
Const maxinputvals As Integer = 3 'The number of search values you want to be looking for
ReDim searcharray(1 To maxinputvals) As Integer 'VBA doesn't need to start at 0
ReDim findarray(1 To maxinputvals) As String 'VBA doesn't need to start at 0
i = 0 'not needed but always nice to make sure
Do
i = i + 1 'add 1 to the count-var
If i > maxinputvals Then Exit Do 'if the count-var si bigger than max number of searchvalues quit the loop
If data.Cells(i, 3) <> "" Then 'check if cells is not empty
searcharray(i) = data.Cells(i, 3).Value 'safe the searchvalue
Else
MsgBox "Searchvalue #" & i & " is missing." 'exit the sub if a searchvalue is missing
Exit Sub
End If
Loop
Set searchrange = data.Range("A1:A5000")
For Each cell In searchrange 'go through the whole range
If cell.Value <> "" Then 'check is cell is empty
For i = 1 To maxinputvals 'if not, check if match with one of the searchvals
If cell.Value = searcharray(i) Then
findarray(i) = findarray(i) & ", " & cell.Row 'append your findarray string
End If
Next i
Else
Exit For 'if cell is empty exit the loop
End If
Next cell
For i = 1 To maxinputvals
findarray(i) = Mid(findarray(i), 3) 'delete the first ", "
data.Cells(i, 4) = findarray(i) 'output the findstring
Next i
End Sub

Excel VBA, Autofilter with the output from a loop

Sub Projektlaufzeit()
Dim Datum1 As Date, msg As String
Dim Datum2 As Date
Dim Rest As Long
Dim Projektname As String
Dim i As Integer
Dim c As Integer
Dim ber As Range
Projektname = Range("A2")
Datum1 = Date
'Datum2 = Tabelle1.Range("C2")
c = Sheets("tabelle1").UsedRange.SpecialCells(xlCellTypeLastCell).Column
For i = 2 To c
Projektname = Cells(i, 1)
Datum2 = Cells(i, 3)
Rest = DateDiff("d", Datum1, Datum2)
If Rest > 7 And Rest < 30 Then MsgBox "something"
If Rest >= 0 And Rest <= 7 Then MsgBox "something"
If Rest <= 0 Then MsgBox "something"
Next i
Dim FilterArray
Dim List As Range
Set List = ActiveSheet.Range("A:A")
List.AutoFilter
FilterArray = Array(Projektname)
List.AutoFilter Field:=1, Criteria1:=Array(FilterArray)
End Sub
So that is my code so far. I have a Loop which tells me when a certain project will come to an end. That works so far.
The next step is, that the macro will autofilter all projects that have a remaining duration of < 30 days.
In my code obviously only the last project that was affected by the loop will be filtered. Is it possible to create an array with all affected projects?
I attached a screenshot of the Excel Worksheet.
Thanks in advance.
If you imagine that all your dates are numbers and your target is to create an array of the values in column A, that
correspond to some condition, then this is a possible input:
With the code below, the condition is translated as:
Projects with remaining duration less or equal than 2 days and not finished with today's date.
Option Explicit
Sub ProjectTime()
Dim lngDateToday As Long
Dim lngRemainingDuration As Long
Dim lngLastRow As Long
Dim lngCounter As Long
Dim varProjects() As Variant
Dim blnFirst As Boolean
blnFirst = True
lngDateToday = Range("D2")
lngRemainingDuration = Range("E2")
lngLastRow = 13
ReDim varProjects(0)
For lngCounter = 2 To lngLastRow
If Cells(lngCounter, 3) < (lngDateToday + lngRemainingDuration) And _
Cells(lngCounter, 3) >= lngDateToday Then
If Not blnFirst Then
ReDim Preserve varProjects(UBound(varProjects) + 1)
End If
blnFirst = False
varProjects(UBound(varProjects)) = Cells(lngCounter, 1)
End If
Next lngCounter
For lngCounter = LBound(varProjects) To UBound(varProjects)
Debug.Print varProjects(lngCounter)
Next lngCounter
End Sub
Thus, projects E,G and I (highlighted) are the one matched and added to the array of values. As far as we are not using a collection, but an array, I am redim-ing and preserving on every step (except for the first one).
To filter the array, you need to add the array as a parameter to the filter. Add the following to the end of the code:
Dim List As Range
Set List = ActiveSheet.Range("A:A")
List.AutoFilter
List.AutoFilter field:=1, Criteria1:=Array(varProjects), Operator:=xlFilterValues
This is how it should look like:

Debugging Using Arrays in VBA

I need to write a program that stores names (located in the 2nd column) in an array when the name has an "X" in the 8th column, but I'm having trouble with putting names in the array. When I run it now, I get a blank value for the value in the array. After some debugging, I found out that the i value that tells which spot in the array is selected turns out to be 0, which is not what I wanted.
Here's the code:
Dim rowCount As Integer
Dim duplicateNames(100) As String
Dim duplicateNameCounter As Integer
duplicateNameCounter = 0
'Count the number of rows'
rowCount = WorksheetFunction.CountA(Range("B1:B5000"))
'Find the names with an X next to them and put them in the array'
For i = 1 To 100
If Cells(i, 8).Value = "X" Then
MsgBox ("Found a name to put in the array!")
duplicateNames(i) = Cells(i, 2).Value
duplicateNameCounter = duplicateNameCounter + 1
End If
Next i
'Show the contents of the array'
For i = 1 To duplicateNameCounter
MsgBox ("Here's the slot in the array: " & i & vbNewLine & "Here's the name: " & duplicateNames(i))
Next i
This is my first time using arrays in VBA, so I think that's where my problem is. I have a background in C++ arrays, but these don't seem too different.
Any help would be appreciated. Thanks!
You're not incrementing duplicateNameCounter the same way you're incrementing your For Each loop. I think that is the problem.
Assume you have an "X" in row 1 and also in row 100, but that the rest of the cells in your column 8 are blank (or whatever, they don't have the "X").
At the end of this block, i will be 100, and there will be names only in slots 1 and 100. HOWEVER duplicateNameCounter will only be value of 2.
For i = 1 To 100
If Cells(i, 8).Value = "X" Then
MsgBox ("Found a name to put in the array!")
duplicateNames(i) = Cells(i, 2).Value
duplicateNameCounter = duplicateNameCounter + 1
End If
Next i
So therefore when you do this, you're basically doing For i = 1 to 2, and that is going to not give you the results you expected -- because in order to display correctly the second duplicate, it would have to hit the 100th slot in the array, which it will never do.
For i = 1 To duplicateNameCounter
MsgBox ("Here's the slot in the array: " & i & vbNewLine & "Here's the name: " & duplicateNames(i))
Next i
I think that the comment from #chancea above should resolve the problem.
There were a few items that prevented successful execution of your code in excel.
Option Explicit is recommended to be used because it will force you to declare all variables and is considered a good programming practice.
Option Explicit
Public Sub asdfasdfasdf()
Dim rowCount As Integer, i As Integer
Dim duplicateNames() As String
Dim duplicateNameCounter As Integer
Setting the counter to 0 allows the array of store values to not have empty values
duplicateNameCounter = 0
Your range formula was only looking for 5000 rows of data, so it has been changed to scan the entire column to prevent missed records
'Count the number of rows'
rowCount = WorksheetFunction.CountA(Range("B:B"))
You were not searching for lower and upper case X's on the test.
'Find the names with an X next to them and put them in the array'
For i = 1 To rowCount
If Cells(i, 8).Value = "X" Or Cells(i, 8).Value = "x" Then
duplicateNameCounter = duplicateNameCounter + 1
Resizing the array was added so that the size of the array would show the number of stores found
ReDim Preserve duplicateNames(duplicateNameCounter)
Debug.Print "Found a name to put in the array! " & Cells(i, 2).Value
You were not using the duplicateNameCounter value on the duplicateNames array.
duplicateNames(duplicateNameCounter) = Cells(i, 2).Value
End If
Next i
'Show the contents of the array'
For i = 1 To duplicateNameCounter
MsgBox "Here's the slot in the array: " & i & vbNewLine & "Here's the name: " & duplicateNames(i)
Next i
End Sub
I wrote the debugging information to the immediate window to speed up running of the code, this make troubleshooting more efficient.

Resources