Excel VBA using an array to speed up code - arrays

I am trying to create an array, store values in the array and then write the values of the array to a spreadsheet in VBA. This codes takes 1+ hour to run on my computer and I think that an array could really speed up the code.
However, I need help with creating the array, populating the array from the comboboxes and finally write the values of the array to the worksheet.
Create an n-dimensional array
Fill the n-dimensional array with the values of the ComboBoxes.
Iterate through all ComboBoxes.
Store values in the array
Write values from the array to the spreadsheet
Sub WantToUseArray()
Dim k As Integer
Dim l As Integer
Sheets("Test").ComboBox1.ListIndex = 0
For l = 0 To 25
Sheets("Test").ComboBox3.ListIndex = l
Sheets("Test").ComboBox2.ListIndex = 0
For n = 0 To 25
Sheets("Test").ComboBox4.ListIndex = n
Sheets("Points").Select
Dim LR As Long
LR = Cells(Rows.Count, 1).End(xlUp).Row + 1
Cells(LR, "A").Value = Sheets("Test").Range("G5").Value
Cells(LR, "B").Value = Sheets("Test").Range("G6").Value
Cells(LR, "C").Value = Sheets("Test").Range("O5").Value
Cells(LR, "D").Value = Sheets("Test").Range("O6").Value
Cells(LR, "E").Value = Sheets("Test").Range("X5").Value
Cells(LR, "F").Value = Sheets("Test").Range("X6").Value
Cells(LR, "G").Value = Sheets("Test").Range("G6").Value + Sheets("Test").Range("X6").Value
Cells(LR, "H").Value = Sheets("Test").Range("X6").Value + Sheets("Test").Range("G6").Value
Cells(LR, "I").Value = Sheets("Test").Range("K40").Value
Cells(LR, "J").Value = Sheets("Test").Range("K41").Value
Cells(LR, "K").Value = Sheets("Test").Range("K51").Value
Cells(LR, "L").Value = Sheets("Test").Range("K52").Value
Next
Next
End Sub

This code goes through each combobox in a given worksheet, generates an array that contains the list values for each comobox list, then prints all of the contents into that first column. myArray only has a single dimension. Its contents are other arrays. If the comoboxes have different list lengths, a jagged array is created.
To help visualize the arrays, enable the Locals Window by going to view in the menu bar and then selecting Locals Window. See pic below the code.
Option Explicit
Sub main()
Dim ws As Worksheet
Dim mainArray() As Variant
Dim ctrl As Object
Dim numComboBoxes As Long
Set ws = ActiveSheet
numComboBoxes = GetNumberOfComboBoxesInSheet(ws)
mainArray = GenerateJaggedArrayComboBoxListValues(ws, numComboBoxes)
PrintArray ws, mainArray
End Sub
Function GetNumberOfComboBoxesInSheet(ByRef ws As Worksheet) As Long
Dim ctrl As Object
For Each ctrl In ws.OLEObjects
If TypeName(ctrl.Object) = "ComboBox" Then
GetNumberOfComboBoxesInSheet = GetNumberOfComboBoxesInSheet + 1
End If
Next ctrl
End Function
Function GenerateJaggedArrayComboBoxListValues(ByRef ws As Worksheet, ByVal numComboBoxes As Long) As Variant()
Dim ctrl As Object
Dim tempPrimaryArray() As Variant
Dim tempArray() As Variant
Dim x As Long
Dim y As Long
Dim listNum As Long
ReDim tempPrimaryArray(0 To numComboBoxes - 1)
x = 0
For Each ctrl In ws.OLEObjects
If TypeName(ctrl.Object) = "ComboBox" Then
y = 0
For listNum = 0 To ctrl.Object.ListCount - 1
ReDim Preserve tempArray(0, 0 To y)
tempArray(0, y) = ctrl.Object.List(listNum, 0)
y = y + 1
Next listNum
tempPrimaryArray(x) = tempArray
Erase tempArray
x = x + 1
End If
Next ctrl
GenerateJaggedArrayComboBoxListValues = tempPrimaryArray()
End Function
Sub PrintArray(ByRef ws As Worksheet, ByRef mainArray As Variant)
Dim counter As Long
Dim x As Long
Dim y As Long
Dim tempArray() As Variant
counter = 1
For x = LBound(mainArray, 1) To UBound(mainArray, 1)
tempArray = mainArray(x)
For y = LBound(tempArray, 2) To UBound(tempArray, 2)
ws.Range("A" & counter) = tempArray(0, y)
counter = counter + 1
Next y
Next x
End Sub

Related

Splitting an Array with many Elements into 4 Parts for Output to a Worksheet

There are some questions about splitting arrays but in my case something goes wrong when I want to output the arrays onto the Worksheet. Also, my solution seems a bit complicated.
My goal is to split a 1-dimensional array with 2.5 mln elements in 4 parts to be able to easily output it to a Worksheet (625,000 rows, 4 columns).
SomeSub() is where the data originates, in this case "i Mod 99" generates some "random" numbers to see some output on the Worksheet. SomeSub() calls the sub SplitArray() which is very the splitting happens. I only have data in a 1-dimensional array but I thought I need to use a 2-dimensional one so that I can get the values from columns into rows by transposing them. Not sure this is actually needed but it works to some degree.
Sub SomeSub()
Dim i As Long
Dim bigarr(1, 2500000) As Integer
Dim timing As Single
timing = Timer
For i = 1 To 2500000
bigarr(1, i) = i Mod 99
Next i
Call SplitArray(bigarr)
Debug.Print Format(Timer - timing, "0.0") & " seconds"
End Sub
Sub SplitArray(ByRef arr0() As Integer)
Dim i As Long
Dim arr1(1, 625000) As Integer
Dim arr2(1, 625000) As Integer
Dim arr3(1, 625000) As Integer
Dim arr4(1, 625000) As Integer
For i = 1 To 625000: arr1(1, i) = arr0(1, i): Next i
For i = 625001 To 1250000: arr2(1, i - 625000) = arr0(1, i): Next i
For i = 1250001 To 1875000: arr3(1, i - 1250000) = arr0(1, i): Next i
For i = 1875001 To 2500000: arr4(1, i - 1875000) = arr0(1, i): Next i
Dim vektor As Variant
Worksheets("Output").Select
vektor = Application.WorksheetFunction.Transpose(arr1)
Range(Cells(11, 1), Cells(625010, 1)).Value = vektor
vektor = Application.WorksheetFunction.Transpose(arr2)
Range(Cells(11, 2), Cells(625010, 2)).Value = vektor
vektor = Application.WorksheetFunction.Transpose(arr3)
Range(Cells(11, 3), Cells(625010, 3)).Value = vektor
vektor = Application.WorksheetFunction.Transpose(arr4)
Range(Cells(11, 4), Cells(625010, 4)).Value = vektor
End Sub
The problem is that my approach works only until row 35186 but not until row 625,010.
Currently the whole procedure takes about 1.9 seconds using 1 thread. This is usually fast enough but a quicker or simpler solution to splitting a "long array" would also be appreciated.
Change your arrays to be vertical instead of horizontal and you can avoid Application.Transpose which has a limit to the number of items it allows:
Sub SplitArray(ByRef arr0() As Integer)
Dim i As Long
Dim arr1(625000, 1) As Integer
Dim arr2(625000, 1) As Integer
Dim arr3(625000, 1) As Integer
Dim arr4(625000, 1) As Integer
For i = 1 To 625000: arr1(i, 1) = arr0(1, i): Next i
For i = 625001 To 1250000: arr2(i - 625000, 1) = arr0(1, i): Next i
For i = 1250001 To 1875000: arr3(i - 1250000, 1) = arr0(1, i): Next i
For i = 1875001 To 2500000: arr4(i - 1875000, 1) = arr0(1, i): Next i
With Worksheets("Output")
.Range(.Cells(11, 1), .Cells(625010, 1)).Value = arr1
.Range(.Cells(11, 2), .Cells(625010, 2)).Value = arr2
.Range(.Cells(11, 3), .Cells(625010, 3)).Value = arr3
.Range(.Cells(11, 4), .Cells(625010, 4)).Value = arr4
End With
End Sub
But you really only need one output array with 4 columns:
Sub SplitArray(ByRef arr0() As Integer)
Dim i As Long
Dim arr1(625000, 4) As Integer
For i = 1 To 625000: arr1(i, 1) = arr0(1, i): Next i
For i = 625001 To 1250000: arr1(i - 625000, 2) = arr0(1, i): Next i
For i = 1250001 To 1875000: arr1(i - 1250000, 3) = arr0(1, i): Next i
For i = 1875001 To 2500000: arr1(i - 1875000, 4) = arr0(1, i): Next i
With Worksheets("Output")
.Range(.Cells(11, 1), .Cells(625010, 4)).Value = arr1
End With
End Sub
Split a 1D Array
Simple
The GetSplitOneD function will return the columns in a 2D one-based array whose values can easily be written (copied) to a range e.g.:
rg.Resize(UBound(Data, 1), UBound(Data, 2)).Value = Data
Sub GetSplitOneDtest()
Dim Timing As Double: Timing = Timer
Const nCount As Long = 2500000
Const ColumnsCount As Long = 4
Const dName As String = "Output"
Const dFirstCellAddress As String = "A2"
' Reference the workbook
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim n As Long
' Create the source (sample) array i.e. return the numbers
' from 1 to 'nCount' in a 1D one-based array.
Dim sArr() As Variant: ReDim sArr(1 To nCount)
For n = 1 To nCount
sArr(n) = n
Next n
' Using the 'GetSplitOneD' function, return the split values
' from the source array in the destination array ('dData'),
' a 2D one-based array.
Dim dData() As Variant: dData = GetSplitOneD(sArr, ColumnsCount)
' Write the destination rows count to a variable ('drCount').
Dim drCount As Long: drCount = UBound(dData, 1)
' Reference the destination worksheet ('dws').
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
' Reference the destination first cell ('dfCell').
Dim dfCell As Range: Set dfCell = dws.Range(dFirstCellAddress)
' Calculate the destination clear rows count ('dcrCount'),
' the number of rows to be cleared below the destination ranges.
Dim dcrCount As Long: dcrCount = dws.Rows.Count - dfCell.Row - drCount + 1
' Write the values from the destination array to the destination ranges.
With dfCell.Resize(, ColumnsCount) ' reference the first row
.Resize(drCount).Value = dData ' write
.Resize(dcrCount).Offset(drCount).Clear ' clear below
End With
Debug.Print Format(Timer - Timing, "0.000") & " seconds"
' Inform.
MsgBox "Data split.", vbInformation
End Sub
Function GetSplitOneD( _
SourceOneD() As Variant, _
ByVal ColumnsCount As Long) _
As Variant()
Dim sCount As Long: sCount = UBound(SourceOneD) - LBound(SourceOneD) + 1
Dim drCounts() As Long: ReDim drCounts(1 To ColumnsCount)
Dim drCount As Long: drCount = Int(sCount / ColumnsCount)
Dim Remainder As Long: Remainder = sCount Mod ColumnsCount
If Remainder > 0 Then
drCount = drCount + 1
drCounts(ColumnsCount) = drCount - ColumnsCount + Remainder
Else
drCounts(ColumnsCount) = drCount
End If
Dim c As Long
For c = 1 To ColumnsCount - 1: drCounts(c) = drCount: Next c
Dim dData() As Variant: ReDim dData(1 To drCount, 1 To ColumnsCount)
Dim s As Long: s = LBound(SourceOneD)
Dim dr As Long
For c = 1 To ColumnsCount
For dr = 1 To drCounts(c)
dData(dr, c) = SourceOneD(s)
s = s + 1
Next dr
Next c
GetSplitOneD = dData
End Function
More Flexible
The GetJaggedSplitOneD function will return the columns in a jagged array containing as many 2D one-based one-column arrays as there are columns. Then you could write each column to another place instead of writing them next to each other. In the test sub, you could change the value of the dcGap constant determining how many empty columns should be in-between. If you don't need this additional functionality, use the first function since it's a little bit faster.
Sub GetJaggedSplitOneDtest()
Dim Timing As Double: Timing = Timer
' Define constants.
Const nCount As Long = 2500000
Const ColumnsCount As Long = 4
Const dName As String = "Output"
Const dFirstCellAddress As String = "A2"
Const dcGap As Long = 2 ' empty columns in-between
' Reference the workbook
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim n As Long
' Create the source (sample) array i.e. return the numbers
' from 1 to 'nCount' in a 1D one-based array.
Dim sArr() As Variant: ReDim sArr(1 To nCount)
For n = 1 To nCount
sArr(n) = n
Next n
' Using the 'GetJaggedSplitOneD' function, return the split values
' from the source array in the destination array ('dJAG'), a jagged array
' containing 4 ('ColumnsCount') same-sized 2D one-based one-column arrays.
Dim dJag() As Variant: dJag = GetJaggedSplitOneD(sArr, ColumnsCount)
' Write the destination rows count to a variable ('drCount').
Dim drCount As Long: drCount = UBound(dJag(1), 1)
' Reference the destination worksheet ('dws').
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
' Reference the destination first cell ('dfCell').
Dim dfCell As Range: Set dfCell = dws.Range(dFirstCellAddress)
' Calculate the destination clear rows count ('dcrCount'),
' the number of rows to be cleared below the destination ranges.
Dim dcrCount As Long: dcrCount = dws.Rows.Count - dfCell.Row - drCount + 1
' Write the values from the destination array to the destination ranges.
For n = 1 To ColumnsCount
With dfCell
.Resize(drCount).Value = dJag(n) ' write
.Resize(dcrCount).Offset(drCount).Clear ' clear below
End With
Set dfCell = dfCell.Offset(, dcGap + 1)
Next n
Debug.Print Format(Timer - Timing, "0.000") & " seconds"
' Inform.
MsgBox "Data split.", vbInformation
End Sub
Function GetJaggedSplitOneD( _
SourceOneD() As Variant, _
ByVal ColumnsCount As Long) _
As Variant()
Dim sCount As Long: sCount = UBound(SourceOneD) - LBound(SourceOneD) + 1
Dim drCounts() As Long: ReDim drCounts(1 To ColumnsCount)
Dim drCount As Long: drCount = Int(sCount / ColumnsCount)
Dim Remainder As Long: Remainder = sCount Mod ColumnsCount
If Remainder > 0 Then
drCount = drCount + 1
drCounts(ColumnsCount) = drCount - ColumnsCount + Remainder
Else
drCounts(ColumnsCount) = drCount
End If
Dim c As Long
For c = 1 To ColumnsCount - 1: drCounts(c) = drCount: Next c
Dim dJag() As Variant: ReDim dJag(1 To ColumnsCount)
Dim dData() As Variant: ReDim dData(1 To drCount, 1 To 1)
Dim s As Long: s = LBound(SourceOneD)
Dim dr As Long
For c = 1 To ColumnsCount
dJag(c) = dData
For dr = 1 To drCounts(c)
dJag(c)(dr, 1) = SourceOneD(s)
s = s + 1
Next dr
Next c
GetJaggedSplitOneD = dJag
End Function

VBA Arrays - Subscript Out of Range, Having Trouble Looping Array and Loading into New Array

This is a follow up question to my previous VBA question. Someone provided me with a potential solution for a lag in performance, and mentioned instead of looping through the actual cells in each column, transform the columns into Arrays and then load the results into a new Array.
I keep getting "subscript out of range" issues, among other various errors. I've manipulated these Arrays so many times with ReDim and others to try to load the results, but I keep hitting the same issue. You will see some of the code I tried where things are commented out.
How can I properly load these results based on the information I have? I thought at first it was because I was declaring a dynamic, empty Array, so that's why I used the UBound of an array of the same size in a ReDim.
Sub Missing_CAT():
Dim i As Variant
Dim j As Variant
'Dim j As Long
'Dim h As Long
'Dim h As Variant
Dim d As Date
Dim e As Date
Dim f As Date
Dim a As String
Dim ws As Worksheet
Dim rowCount As Long
Dim secondRowCount As Long
Dim oDateArr() As Variant
Dim fromDateArr() As Variant
Dim toDateArr() As Variant
Dim perilArr() As Variant
Dim resultArr() As Variant
Dim cell As Variant
Dim counter As Variant
Dim count As Long
Dim boundary As Long
Dim ub As Integer
rowCount = Worksheets("raw_data_YOA").Cells(Rows.count, "A").End(xlUp).row
oDateArr = Sheets("raw_data_YOA").Range("Q2:Q" & rowCount).Value
ub = UBound(oDateArr)
ReDim resultArr(ub)
count = 0
'For i = 2 To rowCount
For Each i In oDateArr
'd = Worksheets("raw_data_YOA").Cells(i, 17).Value
d = i
For Each ws In Sheets
If ws.Name = "2020" Or ws.Name = "2019" Then
secondRowCount = ws.Cells(Rows.count, "D").End(xlUp).row
fromDateArr = ws.Range("D5:D" & secondRowCount).Value
toDateArr = ws.Range("E5:E" & secondRowCount).Value
perilArr = ws.Range("F5:F" & secondRowCount).Value
' For j = 5 to secondRowCount
'For Each j In fromDateArr
'boundary = UBound(fromDateArr)
For j = 1 To UBound(fromDateArr)
' MsgBox (fromDateArr(j))
e = fromDateArr(j, 1)
f = toDateArr(j, 1)
p = perilArr(j, 1)
'e = ws.Cells(j, 4).Value
' f = ws.Cells(j, 5).Value
If d >= e And d <= f Then
' ReDim Preserve resultArr(1 To UBound(resultArr) + 1)
' resultArr(UBound(resultArr), 1) = p
resultArr(count) = p
Exit For
ElseIf j = UBound(fromDateArr) Then
' Worksheets("raw_data_YOA").Cells(i, 63).Value = "FALSE"
' ReDim Preserve resultArr(1 To UBound(resultArr) + 1)
' MsgBox (UBound(resultArr))
resultArr(count) = "FALSE"
End If
Next j
Else
GoTo NextIteration
End If
count = count + 1
NextIteration:
Next
Next i
counter = 0
For Each cell In Sheets("raw_data_YOA").Range("Q2:Q" & rowCount)
cell.Value = resultArr(counter)
counter = counter + 1
Next
MsgBox ("Done")
End Sub
EDIT:
Specifically, the lines throwing the errors are resultArr(count) = ...

Match 2D arrays and output values of another array

I cannot get to work condition for matching 2D arrays. I have tried another approach and this one is closer to the solution, but still does not produce the outcome.
This is what I want to do:
In sheet1 I have different dates that go through columns and size is uncertain. Below these dates are the values:
In sheet 2, I have a smaller subset of dates (that should exist in sheet1):
Through the code, I want to match the dates in sheet1 and sheet2, and only if match is true, I want to write the corresponding values from sheet1 to sheet2.
This is the outcome:
I want to use Arrays for dates in sheet1 and sheet2 and if they match, write the array of values. But the arrays of dates turn to be empty and so condtion for match does not work. I am not getting any error message as well:
Sub test()
Dim arrAmounts() As Variant
Dim arrDates_w2() As Variant
Dim arrDates_w1() As Variant
Dim Lastcol_w2 As Integer
Dim Lastcol_w1 As Integer
Dim LastRow As Integer
Dim i As Integer
Dim w As Integer
Dim d As Integer
Dim f As Integer
Dim g As Integer
Dim w1 As Worksheet
Dim w2 As Worksheet
Set w1 = Sheets("Sheet1")
Set w2 = Sheets("Sheet2")
LastRow = 17 'last row on both sheets
f = 1
g = 1
With w2
Lastcol_w2 = .Cells(3, Columns.Count).End(xlToLeft).Column
'array of dates in w2
ReDim arrDates_w2(1, Lastcol_w2)
End With
With w1
Lastcol_w1 = .Cells(3, Columns.Count).End(xlToLeft).Column
'Assign arrays:
ReDim arrAmounts(LastRow, Lastcol_w1)
ReDim arrDates_w1(1, Lastcol_w1)
For i = 1 To LastRow
For d = 1 To UBound(arrDates_w1, 2)
arrAmounts(i, d) = .Cells(3 + i, 2 + d)
Next
Next
'Match the dates in worksheets 1 and 2
For i = 1 To LastRow
For w = 1 To UBound(arrDates_w2, 2)
For d = 1 To UBound(arrDates_w1, 2)
If arrDates_w2(1, w) = arrDates_w1(1, d) Then
w2.Cells(i + 3, 2 + w) = arrAmounts(i, f + 3)
End If
Next
Next
Next
End With
End Sub
I would appreciate suggestions.
Please try this code.
Option Explicit
Sub CopyColumns()
Const CaptionRow As Long = 3 ' on all sheets
Const FirstClm As Long = 3 ' on all sheets
Dim WsIn As Worksheet ' Input sheet
Dim WsOut As Worksheet ' Output sheet
Dim DateRange As Range ' dates on WsIn
Dim Cin As Long ' input column
Dim Rl As Long ' last row in WsIn
Dim Cl As Long ' last used column in WsOut
Dim C As Long ' column counter in WsOut
Dim Arr As Variant ' transfer values
Set WsIn = Worksheets("Sheet1")
Set WsOut = Worksheets("Sheet2")
With WsIn
Set DateRange = .Range(.Cells(CaptionRow, FirstClm), .Cells(CaptionRow, .Columns.Count).End(xlToLeft))
End With
With WsOut
Cl = .Cells(CaptionRow, .Columns.Count).End(xlToLeft).Column
For C = FirstClm To Cl
On Error Resume Next
Cin = Application.Match(.Cells(CaptionRow, C).Value2, DateRange, 0)
If Err = 0 Then
Cin = Cin + DateRange.Column - 1
Rl = WsIn.Cells(WsIn.Rows.Count, Cin).End(xlUp).Row
Arr = WsIn.Range(WsIn.Cells(CaptionRow + 1, Cin), WsIn.Cells(Rl, Cin)).Value
.Cells(CaptionRow + 1, C).Resize(UBound(Arr)).Value = Arr
End If
Next C
End With
End Sub
What do you expect ReDim arrDates_w2(1, Lastcol_w2) to be doing? As it stands, it's only re-sizing the number of items that can be held in the array... You need to assign the Range to it: arrDates_w2 = w2.Range("C3:K3").Value for example. This will create a multi-dimensional array.
Then you can loop the items. Here's some sample code to illustrate the principle
Sub GetArrayInfo()
Dim a As Variant, i As Long, j As Long
Dim w2 As Worksheet
Set w2 = Sheets("Sheet2")
a = ws.Range("C3:K3").Value2
Debug.Print UBound(a, 1), UBound(a, 2)
For j = 1 To UBound(a, 2)
For i = 1 To UBound(a, 1)
Debug.Print a(i, j)
Next
Next
End Sub
Try
Sub test()
Dim Ws As Worksheet, Ws2 As Worksheet
Dim c As Integer, j As Integer, p As Integer
Dim i As Long, r As Long
Dim arr1() As Variant, arr2() As Variant
Dim rngDB As Range, rngHead As Range
Set Ws = Sheets("Sheet1")
Set Ws2 = Sheets("Sheet2")
With Ws
c = .Cells(3, Columns.Count).End(xlToLeft).Column
r = .Range("c" & Rows.Count).End(xlUp).Row
Set rngHead = .Range("c3", .Cells(3, c))
arr1 = .Range("c3", .Cells(r, c))
End With
With Ws2
c = .Cells(3, Columns.Count).End(xlToLeft).Column
Set rngDB = .Range("c3", .Cells(r, c))
arr2 = rngDB
End With
For j = 1 To UBound(arr2, 2)
p = WorksheetFunction.Match(arr2(1, j), rngHead, 0)
For i = 2 To UBound(arr2, 1)
arr2(i, j) = arr1(i, p)
Next i
Next j
rngDB = arr2
End Sub

Create an array of rows VBA

New to VBA. I'm trying to create an array of rows.
Basically, I have an entire sheet and want to take all the rows that start with a certain value ("MA") in column 8.
I eventually want to manipulate that array (as if it were a range), and paste it somewhere else in the sheet. Can anyone help? Here's my code so far:
Dim top0M As Variant
ReDim top0M(1 To 1) As Variant
For i = 4 To Rows.Count
If Cells(i, 8).Value Like "MA*" Then
top0M(UBound(top0M)) = Rows(i)
ReDim Preserve top0M(1 To UBound(top0M) + 1) As Variant
End If
Next i
This code runs but I'm not sure how to debug it to know if I even have the right rows inside. Can I paste these rows as if they were a range?
This sets the range and loads the whole into an array then it loads a different array with the lines that you want:
With ActiveSheet 'This should be changed to the name of the worksheet: Worksheets("MySheet")
Dim rng As Range
Set rng = .Range(.Cells(4, 1), .Cells(.Cells(.Rows.Count, 1).End(xlUp).Row, .Cells(4, .Columns.Count).End(xlToLeft).Column))
Dim tot As Variant
tot = rng.Value
Dim top0M As Variant
ReDim top0M(1 To Application.CountIf(.Range("H:H"), "MA*"), 1 To UBound(tot, 2)) As Variant
Dim k As Long
k = 1
Dim i As Long
For i = LBound(tot, 1) To UBound(tot, 1)
If tot(i, 8) Like "MA*" Then
Dim j As Long
For j = LBound(tot, 2) To UBound(tot, 2)
top0M(k, j) = tot(i, j)
Next j
k = k + 1
End If
Next i
End With
'to print to a sheet just assign the values:
Worksheets("sheet1").Range("A1").Resize(UBound(top0M, 1), UBound(top0M, 2)).Value = top0M
Try this code
Sub Test()
Dim x As Variant
x = ActiveSheet.Range("A4").CurrentRegion.Value
x = FilterArray(x, 8, "MA*", True)
ActiveSheet.Range("K14").Resize(UBound(x, 1), UBound(x, 2)).Value = x
End Sub
Function FilterArray(ByVal myRefArr As Variant, ByVal col As Integer, ByVal refValue As String, ByVal equal As Boolean) As Variant
Dim a As Variant
Dim i As Long
Dim j As Long
Dim n As Long
On Error Resume Next
n = 1
If refValue = "" Then
FilterArray = myRefArr
Else
ReDim a(1 To UBound(myRefArr, 1), 1 To UBound(myRefArr, 2))
For i = 1 To UBound(a, 1)
If IIf(equal, UCase(myRefArr(i, col)) Like UCase(refValue), Not (UCase(myRefArr(i, col)) Like UCase(refValue))) Then
For j = 1 To UBound(a, 2)
a(n, j) = myRefArr(i, j)
Next j
n = n + 1
End If
Next i
a = Application.Transpose(a)
ReDim Preserve a(1 To UBound(a, 1), 1 To n - 1)
a = Application.Transpose(a)
FilterArray = a
End If
On Error GoTo 0
End Function

How to unpack 2d array of elements into a 3d array of columns and rows, maybe called a series?

I am using Bloomberg sample code to collect data from Bloomberg through VBA (2d array?) and I have some old vba code that I believe takes a normal 3d array (maybe someone can clarify that for me). The problem is that Bloomberg output an array of elements.
See Bloomberg code below. Then below that is what I want to essentially convert the Bloomberg output into something that the next bit of code will accept.
Private Sub session_ProcessEvent(ByVal obj As Object)
On Error GoTo errHandler
Dim eventObj As blpapicomLib2.Event
Set eventObj = obj
If Application.Ready Then
If eventObj.EventType = PARTIAL_RESPONSE Or eventObj.EventType = RESPONSE Then
Dim it As blpapicomLib2.MessageIterator
Set it = eventObj.CreateMessageIterator()
Do While it.Next()
Dim msg As Message
Set msg = it.Message
Dim securityData As Element
Dim securityName As Element
Dim fieldData As Element
Set securityData = msg.GetElement("securityData")
Set securityName = securityData.GetElement("security")
Set fieldData = securityData.GetElement("fieldData")
Sheet1.Cells(currentRow, 4).Value = securityName.Value
Dim b As Integer
For b = 0 To fieldData.NumValues - 1
Dim fields As blpapicomLib2.Element
Set fields = fieldData.GetValue(b)
Dim a As Integer
Dim numFields As Integer
numFields = fields.NumElements
For a = 0 To numFields - 1
Dim field As Element
Set field = fields.GetElement(a)
Sheet1.Cells(currentRow, a + 5).Value = field.Name & " = " & field.Value
Next
currentRow = currentRow + 1
Next b
Loop
' skip a row for next security
currentRow = currentRow + 1
End If
End If
Exit Sub
errHandler:
MsgBox Err.Description
End Sub
This is the next bit of code I want the Bloomberg output to feed into.
Option Explicit
Dim Count() As Variant
Dim AdjCount() As Variant
Dim Rev() As Variant
Dim Conf() As Variant
Dim ncount() As Integer
Sub CreateSetupsBUY(series As Variant)
Dim x As Integer
Dim Y As Integer
Dim temp1 As Variant
Dim temp2 As Variant
Dim temp3 As Variant
Dim temp4 As Integer
Dim temp5 As Variant
ReDim Count(UBound(series))
ReDim AdjCount(UBound(series))
ReDim Rev(UBound(series))
ReDim Confn(UBound(series))
ReDim ncount(UBound(series))
For x = LBound(series) To UBound(series)
ReDim temp1(UBound(series(x)))
ReDim temp2(UBound(series(x)))
ReDim temp3(UBound(series(x)))
temp4 = 0
ReDim temp5(UBound(series(x)))
For Y = LBound(series(x)) + 5 To UBound(series(x))
If IsNumeric(series(x)(Y, 1)) Then
If series(x)(Y, 4) < series(x)(Y - 4, 4) Then
temp1(Y) = 1 + temp1(Y - 1)
Else
temp1(Y) = 0
End If
If series(x)(Y, 4) > series(x)(Y - 4, 4) Then
temp5(Y) = 1 + temp5(Y - 1)
Else
temp5(Y) = 0
End If
If temp1(Y) > 9 Then
temp2(Y) = 0
Else
temp2(Y) = temp1(Y)
End If
If temp1(Y) = 9 Then
temp4 = temp4 + 1
End If
If series(x)(Y - 1, 4) >= series(x)(Y - 5, 4) Then
temp3(Y) = 1
Else
temp3(Y) = 0
End If
Else
temp1(Y) = 0
temp2(Y) = 0
temp3(Y) = 0
temp4 = 0
temp5(Y) = 0
End If
Next Y
Count(x) = temp1
AdjCount(x) = temp2
Conf(x) = temp3
ncount(x) = temp4
Rev(x) = temp5
Next x
Call CreateCount(series, Count, Conf, ncount, Rev)
End Sub
When I tried connecting the two I get a type error. I assume its because of the way the Bloomberg array is created and unpacked.
Possible solution I have yet to try is to unpack the Bloomberg array and some how build a basic column row array while the Bloomberg array is unpacking.

Resources