Iterate through Array (strange dimension) - arrays

I have an array as shown in the screenshot:
I am trying to iterate through this array, but I am unable to manage the dimension setting. Haven't seen an array like that before.
It will be creating while using the Split-function of VBA. How am I able to iterate through to second dimension?
Code snippet:
Dim arrTemp() As Variant: arrTemp = tblUserInput.DataBodyRange
Dim arr() As Variant
Dim arrtemp_Sheet() As Variant
Dim arrtemp_Control() As Variant
iCounter = 0
For i = LBound(arrTemp) To UBound(arrTemp)
If Not arrTemp(i, 5) = "" Then
iCounter = iCounter + 1
ReDim Preserve arrtemp_Sheet(1 To iCounter)
ReDim Preserve arrtemp_Control(1 To iCounter)
arrtemp_Sheet(iCounter) = Split(arrTemp(i, 5), ";")
arrtemp_Control(iCounter) = Split(arrTemp(i, 6), ";")
End If
Next i
Dim arrFinal_Sheet() As Variant
For i = LBound(arrtemp_Sheet) To UBound(arrtemp_Sheet)
For j = LBound(arrFinal_Sheet(i)) To UBound(arrFinal_Sheet(i)) <-- Error!
Debug.Print arrFinal_Sheet(i, j)
Next j
Next i
Background information:
I need all entries in that list being populated into an array one by one. and if a cell contains a ";", then I need to split it and put it also one after another into the array.
This is why I first create a temporary Array which collects the sheets and another temporary array which collects the controls names. I then want to merge them into a final array. Maybe there is even a better approach?

Related

Filtering out Numbers from Array

So I have an Array called TagOptions - it contains numeric values according to a pervious if statement. In order to take out values I didn't want I gave the undesired values a place holder value of 0. I am now trying to filter out this value but can't find anything online that is helpful.
Will paste the entire function for context but more interested in just filtering out the placeholder zeros from my array.
Sorry if this is novice but I am very new to this:
Private Sub CommandButton4_Click()
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("TEST")
lrow = sh.Cells(Rows.count, 1).End(xlUp).Row
Dim splitstring As String
Dim holder As String
Dim myarray() As String
Dim strArrayNumber() As Integer
Dim strArrayTag() As String
Dim TagOptions() As Integer
Dim TagOptions2() As Integer
ReDim strArrayNumber(1 To lrow) As Integer
ReDim strArrayTag(1 To lrow) As String
'Initial for loop splitting tags and removing any tags with text (MV-4005A)
'Transfering those remaining tag numbers into array if they match equip selected
For a = 1 To lrow
If sh.Cells(a, 1).Value <> vbNullString Then
splitstring = sh.Cells(a, 1).Value
myarray = Split(splitstring, "-")
strArrayTag(a) = myarray(0)
End If
If IsNumeric(myarray(1)) = False Then
myarray(1) = 0
End If
If strArrayTag(a) = TagNumber1.Value Then 'Only stored if has selected Equipment tag
strArrayNumber(a) = myarray(1)
End If
Next a
'Sort Created Array
Quicksort strArrayNumber, LBound(strArrayNumber), UBound(strArrayNumber)
ReDim TagOptions(1000 To 2000) As Integer
Dim j As Integer
For j = 1000 To 2000
For b = 1 To UBound(strArrayNumber)
If strArrayNumber(b) = j Then
TagOptions(j) = 0
Exit For
Else
TagOptions(j) = j
End If
Next b
sh.Cells(j, 8) = TagOptions(j)
Next j
Quicksort TagOptions, LBound(TagOptions), UBound(TagOptions)
For f = LBound(TagOptions) To UBound(TagOptions)
sh.Cells(f, 9) = TagOptions(f)
Next f
**TagOptions2 = Filter(TagOptions, "0", False, vbDatabaseCompare)**
Me.ComboBox1.List = TagOptions
End Sub
Thnak you in advance for any help.
tl;dr entire code, just note that VBA's Filter() function applied on a "flat" 1-dim array only executes a partial character search finding "0" also in strings like e.g. "10" or "205", what definitely isn't what you want to do :-;
Btw, if your initial array is a 2-dim array, there are number of answers at SO how to slice data from a 2-dim array and transpose or double transpose them to a 1-dim array needed as starting point.
Solving the actual core question how to filter out zero-digits
To succeed in filtering out zeros in a 1-dim array, simply use the following function via the Worksheetfunction FilterXML (available since vers. 2013+):
tagOptions = WorksheetFunction.FilterXML("<t><s>" & _
Join(tagOptions, "</s><s>") & "</s></t>", _
"//s[not(.='0')]")
resulting in a 1-based 2-dim array.
If you prefer, however to get a resulting 1-dim array instead, simply transpose it via tagOptions = Application.Transpose(tagOptions) or tagOptions = WorkSheetFunction.Transpose(tagOptions).
You can find an excellent overview at Extract substrings ... from FilterXML

how to populate and array with a loop

I have a strings in column "C", starting at C2 (for example: Cat, Dog, Bird, etc...) and I don't know how many. So I am using a LRow function to find the last row with data. Currently, the last row is C63 but this is expected to be different if I run the subroutine next week or next month (Hence why I said "I don't know how many"). I want to create an array for example RTArr = Array("Cat", "Dog", "Bird", etc...) So... I was thinking something like:
Dim RTArr As Variant
LRow = r.End(xlDown).Offset(x, y).Row
With ActiveSheet
For i = 2 To LRow
str = .Range("C" & i).Value
Next i
End With
Can I populate the array with something like:
Dim RTArr As Variant
LRow = r.End(xlDown).Offset(x, y).Row
With ActiveSheet
For i = 2 To LRow
ArrNum = (i - 1)
str = .Range("C" & i).Value
RTArr(ArrNum) = str
Next i
End With
Or does this not work because of the unknown size of the array? Or do I have to use "amend" in the loop? Would I be better off using a "collection" in this case? Or going about it some other way? Can I simply set a range of cells as an array without needing to loop?
If you declare a dynamic array at first (without the size), you need to ReDim it to the needed size before populating it, which in your case will be the number of rows e.g. ReDim RTArr(numberofitems). Or use a two dimensional array ReDim RTArr(numbercolumns, numberrows).
Remember that standard arrays begin at element 0, but you can define it however you like.
Remember that when inputting ranges into array Excel creates by default a two-dimensional array
More advanced techniques are possible of course, you can do some more research about VBA arrays regarding those:
1) you could ReDim the array after each element added inside of the loop, but this is mostly useful for one dimensional arrays.
2) you could define a much bigger size of array than needed before populating it, populate it, and then shrink the array to the actual size needed.
3) note that when using two (or more) dimensions ReDim Preserve works only on the last dimension.
Pseudo code for the basic populating:
Dim arr() as Variant
'we know we want to populate array with 10 elements
ReDim arr(1 to 10)
For i = 1 to 10
'This part will insert the count from the loop into the count position in array
' eg. first element of array will be a 1, second a 2 etc. until 10
arr(i) = i
Next i
If your version of Excel supports the TEXTJOIN function:
Sub Kolumn2Array()
Dim r As Range
Dim N As Long
Dim RTArray
Dim comma As String
comma = ","
N = Cells(Rows.Count, "C").End(xlUp).Row
Set r = Range("C2:C" & N)
With Application.WorksheetFunction
RTArray = Split(.TextJoin(comma, True, r), comma)
End With
End Sub

How do I copy this dynamic array into a spreadsheet and why don't boilerplate answers work for me?

I have written a VBA script to filter entries in an Excel table based on the contents of another one. I understand that although my table contains multiple fields (columns) they are contained within a 1D dynamic array.
I assigned a range in a workbook, and then resized this to reflect the size of the dynamic array. I then try to bulk assign the contents of the dynamic array to the range.
Sub generate_motor_list_from_QlikView_data()
Dim tags As Variant
Dim mtrs() As Variant
Dim msng() As Variant
Dim i As Integer
Dim j As Integer
Dim k As Integer
Dim rng As Range
Dim mtrtbl As Range
ReDim Preserve mtrs(i)
ReDim Preserve msng(j)
tags = Worksheets("Backend").Range("Tags[Tag]")
For Each Tag In tags
Set rng = Worksheets("QlikView").Range("QlikView[Tag]").Find(What:=Tag, LookIn:=xlValues, LookAt:=xlWhole)
If rng Is Nothing Then
msng(j) = Tag
j = j + 1
ReDim Preserve msng(j)
' do something !
Else
Set mtrs(i) = Worksheets("QlikView").ListObjects("QlikView").ListRows(rng.Row - 1)
i = i + 1
ReDim Preserve mtrs(i)
End If
Next Tag
Set mtrtbl = Worksheets("Backend").Range("F18")
mtrtbl.Resize(UBound(mtrs, 1), 1) = mtrs
End Sub
The debugger brings up this message, on the line mtrtbl.Resize(UBound(mtrs, 1), 1) = mtrs
Run-time error '1004':
Application-defined or object-defined error"

How do I feed an array of worksheet names into VBA Sheets.Copy?

I have this code that populates an array with worksheet names, given a condition:
Dim lng_Counter As Long
Dim arr_wks() As Variant
lng_Counter = 1
For Each wks In ThisWorkbook.Worksheets
If Left(wks.Name, 2) = "Hi" Then
ReDim Preserve arr_wks(lng_Counter)
arr_wks(lng_Counter) = wks.Name
lng_Counter = lng_Counter +1
End if
Next wks
I would then like copy these worksheets to a new workbook and so I have tried something like this:
Sheets(arr_wks()).Copy
Which isn't working. The only way I can get it to work is to write out:
Sheets(Array(arr_wks(1),arr_Wks(2),...)).Copy
Which isn't useful as the size of the array will change depending on the number of sheets that meet the condition at a given time.
How can I feed the array into a Sheets(arr).Copy type argument?
You end up with an error where the first element (with an index of zero) is empty.
You can fix that with
lng_Counter = 0
, or
ReDim Preserve arr_wks(1 to lng_Counter)
, or
Option Base 1
on top.

Trouble filtering out rows on one worksheet based on an array with values from another worksheet in VBA

My intention was to have the following code compile data from my "Low CPM 1" worksheet into an array and then filter my active worksheet based on this array. While the macro does seem to affect the filters, none of the values get filtered out. Any help on this matter would be greatly appreciated
Sub Macro1()
Dim CPM1Array(0 To 300) As Variant
For i = 2 To UBound(CPM1Array)
CPM1Array(i) = Sheets("Low CPM 1").Cells(i, 2).Value
Next i
ActiveSheet.Range("$A$1:$H$251").AutoFilter Field:=3, Criteria1:=("<>1 to Ubound(CPM1Array)"), Operator:=xlFilterValues
End Sub
There is no simple way with autofilter to achieve what you want. You cannot use Criteria1:="<>MyArray"
Alternative
We know which values we do not want. We can find out what are the values of the relevant column
Simply store the values of the relevant column in an array and then remove the unnecessary values from it by comparing it with the array which has values we do not want.
Remove blank cells from the array
Pass the final array to the autofilter.
In Action
Let's say our worksheet looks like as shown in the below image. I am taking an example of only 15 rows.
Code
Sub Sample()
Dim ws As Worksheet
Dim MyAr(1 To 5) As String
Dim tmpAr As Variant, ArFinal() As String
Dim LRow As Long
ReDim ArFinal(0 To 0)
Set ws = ActiveSheet
'~~> Creating an array of values which we do not want
For i = 1 To 5
MyAr(i) = i
Next i
With ws
'~~> Last Row of Col C sice you will filter on 3rd column
LRow = .Range("C" & .Rows.Count).End(xlUp).Row
'~~> Storing the values form C in the array
tmpAr = .Range("C2:C" & LRow).Value
'~~> Compare and remove values which we do not want
For i = 1 To LRow - 1
For j = 1 To UBound(MyAr)
If tmpAr(i, 1) = MyAr(j) Then tmpAr(i, 1) = ""
Next j
Next i
'~~> Remove blank cells from the array by copying them to a new array
For i = LBound(tmpAr) To UBound(tmpAr)
If tmpAr(i, 1) <> "" Then
ArFinal(UBound(ArFinal)) = tmpAr(i, 1)
ReDim Preserve ArFinal(0 To UBound(ArFinal) + 1)
End If
Next i
'~~> Filter on values which you want. Change range as applicable
.Range("$A$1:$H$15").AutoFilter Field:=3, Criteria1:=ArFinal, Operator:=xlFilterValues
End With
End Sub
Output

Resources