VBA nested For Each loop through array - syntax - arrays

I have multiple pivot tables on a sheet, I'm wanting to loop through all of the pivot field items on 2 of those pivot tables (tables 4 and 5). I created 2 PivotItems variable objects, put them in an array, and I want to do a nested For Each loop iterating over each object in the array, then iterating over each pivot item in each array object. I keep getting a Run-time error '424': Object required at line 11 For Each PvI in Item
Here's the code:
Dim PvtTbl4, PvtTbl5 As PivotItems
Set PvtTbl4 = Worksheets("Main").PivotTables("PivotTable4").PivotFields("dayname").PivotItems
Set PvtTbl5 = Worksheets("Main").PivotTables("PivotTable5").PivotFields("dayname").PivotItems
Dim PivotArray As Variant
PivotArray = Array(PvtTbl4, PvtTbl5)
Dim PvI As PivotItem
Dim Item As Variant
For Each Item In PivotArray
For Each PvI In Item //<-- error
//do something
Next PvI
Next Item

Related

I need to delete a row from an array if one of the array elements is equal to a value. Using Excel VBA

I have copied an Excel table to an array.
Sub
Dim Mentors As Variant
Mentors = Worksheets("Mentors").ListObjects("Mentors").DataBodyRange.Value
end sub
Now I would like to loop through the Mentors array to find rows with invalid values and delete those rows from the array, but I don't know how to do that.
Then I will put the array back in the table. (That I know how to do).
Deleting a row from an array is a pain, it would be easier to work directly on your table:
Dim tbl As ListObject
Dim x As Long
Set tbl = ActiveSheet.ListObjects("Mentors")
For x = tbl.ListRows.Count to 1 step -1
If your_delete_conditions_go_here Then
tbl.ListRows(x).Delete
End If
Next x

Error when Populating values for ComboBox.List

I'm trying to populate a combo box with UNIQUE values only, no duplicates; which I believe is working fine, but something is wrong with my logic in the second For loop
The below logic goings as follows...
Private Function PopulateComboBoxWeeks()
Dim i As Long
Dim x As Long
Dim LR As Long
Dim ws As Worksheet
Dim SearchNextWeek As String
LR = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Set ws = ActiveSheet
With UserForm1.ComboBox1
''' Fill first slot in ComboBox1 with the value of last row in Column "A"
.AddItem ws.Range("A" & LR).Value
''' Loop to search Column "A" for items to fill with, start on the second last row, since the above line fills the first line
For i = LR - 1 To 2 Step -1
''' Loop to search the ComboBox.List() array
For x = 0 To .ListCount
''' Array list starts at 0
If Not (.List(x) = ws.Range("A" & i).Value) Then
.AddItem ws.Range("A" & i).Value
End If
Next x
Next i
End With
End Function
It's checking the Array list properly, but I'm stuck on the second For loop, if I start at index 0 of my array and it's taking into account the total items in the array with .ListCount. Thus it's giving me the below error...
Run-Time error '381':
Could not get the List property. Invalid property array index
Which could only mean I'm referencing an array item outside of the array size. I've tried doing .ListCount - 1 but this gives me an infinite loop. I think all my logic is sound here except this one item and I'm not sure how to get passed this point.
Iterating any collection as you're changing it is always a bad idea.
Don't loop on anything. Just tell it what range you want to use.
If you can't do that, then you need to first get the unique values into an array (single-dimensional), then assign ComboBox1.List = theArray. Done.
There are two things you want to do:
Figure out what the unique values are
Assign the List property
Don't do these two things in one single nested spaghetti loop. Separate them.
Dim allValues As Variant
'get a single-dimensional array with all the values in the column:
allValues = Application.WorksheetFunction.Transpose(ws.Range("A2:A" & LR).Value)
'let's use built-in collection keys to ensure uniqueness:
Dim uniqueValuesColl As Collection
Set uniqueValuesColl = New Collection
Dim currentIndex As Long
For currentIndex = LBound(allValues) To UBound(allValues)
If Not IsError(allValues(currentIndex)) Then
On Error Resume Next
uniqueValuesColl.Add allValues(currentIndex), Key:=CStr(allValues(currentIndex))
If Err.Number <> 0 Then
' we already have that value
Err.Clear
End If
On Error GoTo 0
End If
Next
'now we know what the unique values are - get them into an array:
ReDim uniqueValues(0 To uniqueValuesColl.Count - 1)
Dim currentItem As Variant
currentIndex = 0
For Each currentItem In uniqueValuesColl
uniqueValues(currentIndex) = currentItem
currentIndex = currentIndex + 1
Next
'just assign the list of unique values
ComboBox1.List = uniqueValues
So I'm iterating all values once, and then the unique values once. But you're currently iterating them once for every single item in the non-unique list. So this solution is O(n+m) where n is the number of non-unique items and m is the number of unique items, whereas your nested loop is O(n2) (the big-O notation of your solution is actually more complicated than that, but I'm no big-O expert).

Filtering 2D Arrays and building second 1D array from it in Excel VBA

I have two columns of dates up to 30k lines. I want to filter for one date in the second column and return all the unique dates from the first column.
I could build this in Access but I don't use Access for anything else so it seems overkill to use that. And partly because I am curious if I can do it in Excel.
I'd prefer not to use a loop because it will be expensive in terms of time to run and I am just learning about arrays and class modules so this is a great example.
There is some background on this already on SOF but it's not detailed enough for me - I'm unfamiliar with Class Modules
Filtering 2D Arrays in Excel VBA
Any help or pointers would be greatly appreciated.
Sub CreateUniqueTradeDatesForAsOfDate_test()
Dim InternalArray As Variant
Dim Rg_Internal As Range
Dim arr As New Collection
Dim myRow As Long
Dim myCol As Long
Set d = CreateObject("Scripting.Dictionary")
'set the range
Set Rg_Internal = Worksheets("Bloomberg").Range("G:H")
'Set the array to the range
InternalArray = Rg_Internal.Value
'Transpose the array
InternalArray = Application.Transpose(InternalArray)
'Create the unique
With CreateObject("scripting.dictionary")
For Each it In InternalArray
d = .Item(it)
Next
d = .Keys ' the array .keys contains all unique keys
End With
'print to the immediate window but all unique values of the array
' not just the unique values from the first column based on
'the criteria from the second column
For Each i In d 'To UBound(10, 1)
Debug.Print i; RowNos
Next i
End Sub

Select items in listbox from array

I currently have a cell with a list separated by commas (1, 2, 3) and the list isn't always the same amount of items. It can be up to 10 items.
I then have a listbox with items 1 - 10 in it.
I want to be able to select the specific items that are in the cell on a form with the listbox on it.
I have started by splitting the cell into an array like this:
Dim Array() As String
Array= Split(ActiveSheet.Range("A1"), ",")
But I can't figure out how to select items in my listbox that match the array.
Try the below Code. I tested it. It worked fine for me.
Sub formdisplay()
Dim valsToSelect
valsToSelect = Split(Range("E6").Value, ",") 'E6 is my cell where i have my value in the form of 5,6,7,9
For Each item In valsToSelect
i = 0
For Each listItem In UserForm1.ListBox1.List
If CStr(listItem) = item Then
UserForm1.ListBox1.Selected(i) = True
Exit For
End If
i = i + 1
Next
Next
UserForm1.Show
End Sub

Sum column values into an array

I need to find a way to sum these columns into the lower row. I'm using VBA for an exercise but I don't seem to get it without relying on referencing to each cell.
The result should be an array in which each item is the sum of the values of the table's column and then print the array into the range shown in the picture.
What happens if the number of rows in the column changes?
This is the code I have tried:
Sub cambios_combobox()
Dim librito As Worksheet
Dim celda As Range
Set librito = ActiveWorkbook.Sheets("Tabla Paquetes")
Set celda = Range("A40")
'Range("Table1[[#All],[Column1]]").Select
Select Case ComboBox1.Text
Case "Deco"
Range("eq_asis").Value = Application.Sum(librito.Range("Tabla2[Asistente fotografĂ­a]"))
Range("eq_asis").HorizontalAlignment = xlRight
...
It goes like that, referencing every single cell in that row, summing values up. I figure there must be another way to do that without so much waste.
The following code will put the totals formulas in that row. It first shows the totals row and then applies a formula in it that sums all visible cells in the current column starting at row 2 (R2C) and ending with the cell right above the sum (R[-1]C). Excel might convert this R1C1 notation to A1 notation when it transfers the formula to the cells. Obviously change Sheet2!R1C2 to whatever other cell you are subtracting from the sum.
Public Sub showTotalsMinusOtherCell()
Dim lst As ListObject
Dim ws As Worksheet
Set ws = ActiveSheet
Set lst = ws.ListObjects("Table1")
lst.ShowTotals = True
lst.TotalsRowRange.FormulaR1C1 = "=Subtotal(109,R2C:R[-1]C)-Sheet2!R1C1"
End Sub

Resources