VBA Dynamic Array without empty space - arrays

I have two arrays: in the first one are names and in the second one there are country codes like this example:
array1(0)="Peter" array2(0)="EN"
array1(1)="John" array2(1)="US"
array1(2)="Sandra" array2(2)="FR"
array1(3)="Margot" array2(3)="DE"
Now, I want to check the from an entry in a textbox1 if its a "FR" available in my arrays,if yes then save the positions in a third new array.
My code looks like this, but it is very bad and it does not work the way I want.
Dim name(0 To 9) As String
array1(0) = "Peter"
array1(1) = "John"
array1(2) = "Sandra"
array1(3) = "Margot"
Dim county(0 To 9)
county(0) = "EN"
county(1) = "US"
county(2) = "FR"
county(3) = "DE"
'Dim ArrayCounter
ArrayCounter = 0
Dim VarArray(9999)
For i = 0 To 9
If county(i) = "DE" Then
'ArrayCounter = ArrayCounter + 1
'MsgBox (array1(i))
VarArray(ArrayCounter) = i
ArrayCounter = ArrayCounter + 1
End If
Next i
MsgBox (UBound(VarArray))
Now, if I check the third array, the array has to look like this:
array3(0)=2 'position of FR in my second array

You can get rid of the empty values in your 0 To 9999 array by redimming it:
If ArrayCounter > 0 Then
ReDim Preserve varArray(0 to ArrayCounter - 1) 'Preserve is important because otherwise it will delete the values
Else
'do what you want to do if no match was found
End If

you may be after the following:
Sub main()
Dim names(0 To 9) As String
names(0) = "Peter"
names(1) = "John"
names(2) = "Sandra"
names(3) = "Margot"
Dim county(0 To 9) As String
county(0) = "EN"
county(1) = "US"
county(2) = "FR"
county(3) = "DE"
Dim ArrayCounter As Long
ArrayCounter = 0
Dim foundArray As Variant
foundArray = county '<--| "copy" the 'county' array into 'foundArray', since this latter won't be bigger than the former
Dim iFound As Long, iCounty As Long
iFound = -1
For iCounty = LBound(county) To UBound(county)
If county(iCounty) = "DE" Then
iFound = iFound + 1 '<-- update the 'foundArray' current counter
foundArray(iFound) = iCounty '<-- update the 'foundArray' current counter content
End If
Next iCounty
If iFound >= 0 Then
ReDim Preserve foundArray(0 To iFound) '<--| if any values have been found, resize 'foundArray' up to the found items counter
Else
Erase foundArray '<--| otherwise erase it
End If
End Sub

Related

VBA Array String Matches

I want to check if the current destination string is located within the destination search array once the origins match up. The outcome is supposed to be all flights between any originSearch city and destinationSearch city and the corresponding flight number
I was playing with a boolean that stores all the true matches but I got confused.
Sub Matches()
Dim nFlights As Integer
Dim origin() As String
'Dim isOwned() As Boolean
Dim flightNumber() As String
Dim destination() As String
Dim iOrigin As Integer
Dim iDestination As Integer
Dim iFlight As Integer
Dim nOrigins As Integer
Dim nDestinations As Integer
Dim originSearch() As String
Dim destinationSearch() As String
Dim i As Integer
Dim x As Integer
Dim m As Integer
With wsData.Range("A1")
nFlights = Range(.Offset(1, 0), .End(xlDown)).Rows.Count
ReDim origin(1 To nFlights)
ReDim flightNumber(1 To nFlights)
ReDim destination(1 To nFlights)
'ReDim isOwned(1 To nFlights)
'stores the origin column in an array
For iOrigin = 1 To nFlights
'isOwned(iOrigin) = False
origin(iOrigin) = .Offset(iOrigin, 0).Value
Next
'stores the destination column in an array
For iDestination = 1 To nFlights
'isOwned(iDestination) = False
destination(iDestination) = .Offset(iDestination, 1).Value
Next
'stores the flight column in an array
For iFlight = 1 To nFlights
'isOwned(iFlight) = False
flightNumber(iFlight) = .Offset(iFlight, 2).Value
Next
End With
With wsData.Range("E1")
nOrigins = Range(.Offset(1, 0), .End(xlDown)).Rows.Count
nDestinations = 4 'Range(.Offset(1, 1), .End(xlDown)).Rows.Count
ReDim originSearch(1 To nOrigins)
ReDim destinationSearch(1 To nDestinations)
For i = 1 To nOrigins
originSearch(i) = .Offset(i, 0).Value
For x = 1 To nDestinations
destinationSearch(x) = .Offset(x, 1).Value
For m = 1 To nFlights
If origin(m) = originSearch(i) And destination(m) = destinationSearch(x) Then
wsData.Range("H1").Offset(i, 0).Value = originSearch(i)
wsData.Range("H1").Offset(x, 1).Value = destinationSearch(x)
wsData.Range("H1").Offset(x, 2).Value = flightNumber(m)
End If
Next m
Next x
Next i
End With
End Sub
I think you can solve the problem with this formula:
=FILTER(AllFlights;IFNA(MATCH(AllFlights[Origin];DesiredOrigin;0)*MATCH(AllFlights[Destination];DesiredDestination;0);0);)
Here:
AllFlights is the name of a table with all possible flights;
DeiredOrigin is the name of a table with origins of interest;
DeiredDestination is the name of a table with destinations of interest;
Multiplication of Matches is the matrix equivalent of the OR operator.
p.s. Instead of IFNA we can use ISNUMBER:
=FILTER(AllFlights;ISNUMBER(MATCH(AllFlights[Origin];DesiredOrigin;0)*MATCH(AllFlights[Destination];DesiredDestination;0));)
There should only be a single nested for loop at the end there.
So for each origin_dest-pair search value,
you're searching each origin_dest-pair record value.
This adds all the flight numbers of matching scenarios into an array and then puts the flight numbers into the next available column.
Also Ranges are essentially Variant() arrays, so you can just assign one to the other, instead of iterating through each value.
Option Compare Text
Sub FindFlightNumbers()
Dim orig() As Variant: orig = Range("A2:A" & Range("A2").End(xlDown).Row)
Dim dest() As Variant: dest = Range("B2:B" & Range("B2").End(xlDown).Row)
Dim flight_nums() As Variant: flight_nums = Range("C2:C" & Range("C2").End(xlDown).Row)
'Turn 2-D arrays into 1-D arrays
orig = Application.Transpose(orig)
dest = Application.Transpose(dest)
flight_nums = Application.Transpose(flight_nums)
Dim orig_search As Range: Set orig_search = Range("E2:E" & Range("e2").End(xlDown).Row)
Dim search_cell As Range, i As Integer
For Each search_cell In orig_search
Dim match_numbers() As Variant
For i = 1 To UBound(orig)
If search_cell.Value = orig(i) And search_cell.Offset(0, 1).Value = dest(i) Then
'If its the first match, init the array
If (Not match_numbers) = -1 Then
ReDim Preserve match_numbers(0)
match_numbers(0) = flight_nums(i)
Else
'Otherwise increment the array
ReDim Preserve match_numbers(UBound(match_numbers) + 1)
match_numbers(UBound(match_numbers)) = flight_nums(i)
End If
End If
Next i
'If the array had found matches, store them; comma-delimited
If Not Not match_numbers Then
search_cell.Offset(0, 2).Value = Join(match_numbers, ",")
End If
Erase match_numbers
Next search_cell
End Sub
Here's an approach using Match() directly against the search values on the worksheet:
Sub Matches()
Dim data, m As Long, rngOrigin As Range, rngDest As Range, m As Long, i As Long
'one array of all data: origin|destination|flight#
data = wsdata.Range("A2", wsdata.Cells(Rows.Count, "C").End(xlUp))
'set search ranges
Set rngOrigins = wsdata.Range("E2", wsdata.Cells(Rows.Count, "E").End(xlUp))
Set rngDest = wsdata.Range("F2", wsdata.Cells(Rows.Count, "F").End(xlUp))
'loop all source data
For m = 1 To UBound(data, 1)
'check Match() against search ranges
If Not IsError(Application.Match(data(m, 1), rngOrigins, 0)) Then
If Not IsError(Application.Match(data(m, 2), rngDest, 0)) Then
i = i + 1
wsdata.Range("H1").Offset(i, 0).Resize(1, 3) = _
Array(data(m, 1), data(m, 2), data(m, 3))
End If
End If
Next m
End Sub

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.

Is it possible to divide a Array in VBA

Is it possible to divide an Array?
Example:
array(2) As String
array(1) = "test1"
array(2) = "test2"
~ Now Split
array1 (contains test1) & array 2 (contains test2)
I want to implement a Binarysearch
You can split like this
Sub split_array()
Dim array1(1 To 2) As String
Dim array2(1 To 2) As String
Dim array3(1 To 2) As String
array1(1) = "Test1"
array1(2) = "Test2"
array2(1) = array1(1)
array3(1) = array1(2)
End Sub
But I suspect that is not the best way to do it. I think you would do much better using 3 (probably long integer) variables to represent positions in the array. 1 to represent the 1st element, 1 to represent the last element and 1 to represent the mid element.
Dim lLowerSearchElement As Long
Dim lUpperSearchElement As Long
Dim lMiddleSearchElement As Long
Dim array1(1 to 999) as string
lLowerSearchElement = 1
lUpperSearchElement = 999
lMiddleSearchElement = (lUpperSearchElement + lLowerSearchElement) / 2
You can then check if the if the element is equal to, greater or less then the middle element and proceed accordingly.
Also remember that you will need to sort your data before attempting to use a binary search and it would be useful if you know about recursive calling.
You also need to test your implementation rigorously as a small mistake could result in the search not working probably.
Edit 22/08/13
The implementation I use for a binary search is given below:
Function bCheckSamplePoint(ByRef lSamplePointArray() As String, ByRef bfound As Boolean, _
ByVal lSamplePoint As String) As Boolean
'byref used for the array as could be slow to keep copying the array, bFound is used by calling procedure
Dim lLowerSearchElement As Long
Dim lUpperSearchElement As Long
Dim lMiddleSearchElement As Long
bfound = False 'False until found
'Set initial limits of the search
lLowerSearchElement = 0
lUpperSearchElement = UBound(lSamplePointArray())
Do While lLowerSearchElement <= lUpperSearchElement And bfound = False
lMiddleSearchElement = (lUpperSearchElement + lLowerSearchElement) / 2
If StrComp(lSamplePointArray(lMiddleSearchElement), lSamplePoint, vbTextCompare) = -1 Then
' 'Must be greater than middle element
lLowerSearchElement = lMiddleSearchElement + 1
ElseIf (lSamplePointArray(lMiddleSearchElement) = lSamplePoint) Then
bfound = True
Else
'must be lower than middle element
lUpperSearchElement = lMiddleSearchElement - 1
End If 'lSamplePointArray(lmiddlesearchlelemnt) < lSamplePoint
Loop 'While lLowerSearchElement <= lUpperSearchElement
ErrorExit:
bCheckSamplePoint = bReturn
Exit Function
As you can see this binary search is only checking to see wether a string is found in an array of strings, but it could be modified for other purposes.
You don't need a split function to do binary search
My VBA version of binary search can be found at
http://fastexcel.wordpress.com/2011/08/02/developing-faster-lookups-part-3-a-binary-search-udf/
Split Array into chunks
Public Function splitArray(ByVal initial_array As Variant, Optional chunk_size As Long = 1) As Variant()
Dim split_array() As Variant
Dim chunk() As Variant
Dim chunk_index As Integer: chunk_index = 0
Dim array_index As Integer: array_index = 1
If UBound(initial_array) > chunk_size Then
For i = 0 To UBound(initial_array)
If (i + 1) / (chunk_size * array_index) = 1 Or i = UBound(initial_array) Then
ReDim Preserve chunk(chunk_index)
chunk(chunk_index) = initial_array(i)
ReDim Preserve split_array(array_index - 1)
split_array(array_index - 1) = chunk
chunk_index = 0
array_index = array_index + 1
Else
ReDim Preserve chunk(chunk_index)
chunk(chunk_index) = initial_array(i)
chunk_index = chunk_index + 1
End If
Next i
splitArray = split_array
Else
ReDim Preserve split_array(0)
split_array(0) = initial_array
splitArray = split_array
End If
End Function

VBA Excel Counting Specific Values

I'm trying to write a program that will loop through cells of a specific column (assigned by the user), find new values in those cells and count how many times a specific value is found. The main problem I'm having right now is that this is hard-coded like below:
Function findValues() As Long
For iRow = 2 To g_totalRow
If (ActiveWorkbook.Sheets(sheetName).Cells(iRow, iCol).Text = "") Then
nullInt = nullInt + 1
ElseIf (someValue1 = "" Or someValue1 = ActiveWorkbook.Sheets(sheetName).Cells(iRow, iCol).Text) Then
someValue1 = ActiveWorkbook.Sheets(sheetName).Cells(iRow, iCol).Text
someInt1 = someInt1 + 1
ElseIf (someValue2 = "" Or someValue2 = ActiveWorkbook.Sheets(sheetName).Cells(iRow, iCol).Text) Then
someValue2 = ActiveWorkbook.Sheets(sheetName).Cells(iRow, iCol).Text
someInt2 = someInt2 + 1
ElseIf (someValue3 = "" Or someValue3 = ActiveWorkbook.Sheets(sheetName).Cells(iRow, iCol).Text) Then
someValue3 = ActiveWorkbook.Sheets(sheetName).Cells(iRow, iCol).Text
someInt3 = someInt3 + 1
ElseIf (someValue4 = "" Or someValue4 = ActiveWorkbook.Sheets(sheetName).Cells(iRow, iCol).Text) Then
someValue4 = ActiveWorkbook.Sheets(sheetName).Cells(iRow, iCol).Text
someInt4 = someInt4 + 1
ElseIf (someValue5 = "" Or someValue5 = ActiveWorkbook.Sheets(sheetName).Cells(iRow, iCol).Text) Then
someValue5 = ActiveWorkbook.Sheets(sheetName).Cells(iRow, iCol).Text
someInt5 = someInt5 + 1
ElseIf (someValue6 = "" Or someValue6 = ActiveWorkbook.Sheets(sheetName).Cells(iRow, iCol).Text) Then
someValue6 = ActiveWorkbook.Sheets(sheetName).Cells(iRow, iCol).Text
someInt6 = someInt6 + 1
ElseIf (someValue7 = "" Or someValue7 = ActiveWorkbook.Sheets(sheetName).Cells(iRow, iCol).Text) Then
someValue7 = ActiveWorkbook.Sheets(sheetName).Cells(iRow, iCol).Text
someInt7 = someInt7 + 1
ElseIf (someValue8 = "" Or someValue8 = ActiveWorkbook.Sheets(sheetName).Cells(iRow, iCol).Text) Then
someValue8 = ActiveWorkbook.Sheets(sheetName).Cells(iRow, iCol).Text
someInt8 = someInt8 + 1
ElseIf (someValue9 = "" Or someValue9 = ActiveWorkbook.Sheets(sheetName).Cells(iRow, iCol).Text) Then
someValue9 = ActiveWorkbook.Sheets(sheetName).Cells(iRow, iCol).Text
someInt9 = someInt9 + 1
ElseIf (someValue10 = "" Or someValue10 = ActiveWorkbook.Sheets(sheetName).Cells(iRow, iCol).Text) Then
someValue10 = ActiveWorkbook.Sheets(sheetName).Cells(iRow, iCol).Text
someInt10 = someInt10 + 1
End If
Next iRow
End Function
Here, if the ActiveCell is blank then the nullInt will get incremented, if the ActiveCell has some value then it'll find which of the variables has that same value or the ActiveCell value will be assigned to one of the variables. I created ten variables strictly for testing purposes but I need to make up to one hundred. I was wondering if there was a way to complete this quickly. The only way I could think of was to create a String array and an Int array and store the values that way. However I'm not sure if this is the best way to get this done.
Edit
This portion is directed specifically to dictionaries. Say there is a specific column titled "State". This contains the 50 North American states. Some of these states are repeated and there is a total of 800 values in this column. How do I keep track of how many times (for example) Texas gets hit?
Thank you,
Jesse Smothermon
You should be able to do this with a Dictionary (see Does VBA have Dictionary Structure?)
This code hasn't been tested but should give you a start.
Function findValues() As Scripting.Dictionary
Dim cellValue
Dim dict As New Scripting.Dictionary
For iRow = 2 To g_totalRow
cellValue = ActiveWorkbook.Sheets(sheetName).Cells(iRow, iCol).Text
If dict.Exists(cellValue) Then
dict.Item(cellValue) = dict.Item(cellValue) + 1
Else
dict.Item(cellValue) = 1
End If
Next iRow
Set findValues = dict
End Function
Sub displayValues(dict As Scripting.Dictionary)
Dim i
Dim value
Dim valueCount
For i = 1 To dict.count
valueCount = dict.Items(i)
value = dict.Keys(i)
ActiveWorkbook.Sheets(sheetName).Cells(i, 3).Text = value
ActiveWorkbook.Sheets(sheetName).Cells(i, 4).Text = valueCount
Next i
End Sub
Sub RunAndDisplay()
Dim dict
Set dict = findValues
displayValues dict
End Sub
I've drafted a code for you, hope it helps. I added comments to make each step clearer for you. I believe that simply setting the proper values in the 1st step might make it work for you.
Still, would worth to understand what the code does to help you in the future.
Hope it fits your needs!
Option Explicit
Sub compareValues()
Dim oSource As Excel.Range
Dim oColumn As Excel.Range
Dim oCell As Excel.Range
Dim sBookName As String
Dim sSheetCompare As String
Dim sSheetSource As String
Dim sUserCol As String
Dim sOutputCol As String
Dim sFirstCell As String
Dim vDicItem As Variant
Dim sKey As String
Dim iCount As Integer
Dim sOutput As String
Dim oDic As Scripting.Dictionary
'1st - Define your source for somevalues and for the data to be compared
sBookName = "Book1"
sSheetCompare = "Sheet1"
sSheetSource = "Sheet2"
sFirstCell = "A1"
sOutputCol = "C"
'2nd - Define the 'somevalues' origin value; other values will be taken
' from the rows below the original value (i.e., we'll take our
' somevalues starting from sSheetSource.sFirstCell and moving to the
' next row until the next row is empty
Set oSource = Workbooks(sBookName).Sheets(sSheetSource).Range(sFirstCell)
'3rd - Populate our dictionary with the values beggining in the sFirstCell
populateDic oSource, oDic
'At this stage, we have all somevalues in our dictionary; to check if the
' valuesare as expected, uncomment the code below, that will print into
' immediate window (ctrl+G) the values in the dictionary
For Each vDicItem In oDic
Debug.Print vDicItem
Next vDicItem
'4th - ask the user for the column he wants to use; Use single letters.
' E.g.: A
sUserCol = InputBox("Enter the column the data will be compared")
'5th - scan the column given by the user for the values in the dictionary
Set oColumn = Workbooks(sBookName).Sheets(sSheetCompare).Columns(sUserCol)
'6th - Now, we scan every cell in the column
For Each oCell In oColumn.Cells
sKey = oCell.Value
'7th - Test the special case when the cell is empty
If sKey = "" Then oDic("Empty") = oDic("Empty") + 1
'8th - Test if the key value exists in the dictionary; if so, add it
If oDic.Exists(sKey) Then oDic(sKey) = oDic(sKey) + 1
'9th - Added to exit the for when row reaches 1000.
If oCell.Row = 1000 Then Exit For
Next oCell
'10th - Now, we print back the counters we found, only for sample purposes
' From now on, is up to you how to use the dictionary :)
iCount = 1
Set oColumn = Workbooks(sBookName).Sheets(sSheetCompare).Columns(sOutputCol)
Set oCell = oColumn.Cells(1, 1)
For Each vDicItem In oDic
If oDic(vDicItem) > 0 Then
oCell.Value = vDicItem
oCell.Offset(0, 1).Value = oDic(vDicItem)
Set oCell = oCell.Offset(1, 0)
End If
Next vDicItem
End Sub
Sub populateDic(ByRef oSource As Excel.Range, _
ByRef oDic As Scripting.Dictionary)
'Ideally we'd test if it's created. Let's just set it for code simplicity
Set oDic = New Scripting.Dictionary
'Let's add an 'empty' counter for the empty cells
oDic.Add "Empty", 0
While Len(oSource.Value) > 0
'If the data is not added into somevalues dictionary of values, we add
If Not oDic.Exists(oSource.Value) Then oDic.Add CStr(oSource.Value), 0
'Move our cell to the next row
Set oSource = oSource.Offset(1, 0)
Wend
End Sub

Redimming arrays in VBA

I have 3 arrays of data, that are filled by reading off of an excel sheet, some of the points of data are missing and as such have just been entered into excel as "NA" so I want to look through my array and find each instance of these NA's and remove them from the array since the information is useless. I need to update all three arrays at the same time.
Sub group_data()
Dim country(), roe(), iCap() As String
Dim i As Integer
For i = 1 To 3357
country(i) = Workbooks("restcompfirm.xls").Worksheets("Sheet1").Range("C1").Offset(i, 0)
roe(i) = Workbooks("restcompfirm.xls").Worksheets("Sheet1").Range("AP1").Offset(i, 0)
iCap(i) = Workbooks("restcompfirm.xls").Worksheets("Sheet1").Range("BM1").Offset(i, 0)
Next i
End Sub
So if I find a "NA" as one of the values in roe or iCap I want to get rid of that piece of data in all there arrays.
Note: I have written this code in Notepad.
Let me know if you face any problem with this.
Sub group_data()
dim totalRows as integer
dim rowNum as integer
dim rowsWithoutNA as integer
dim c1Range as Range
dim ap1Range as Range
dim bm1Range as Range
set c1Range = Workbooks("restcompfirm.xls").Worksheets("Sheet1").Range("C1")
set ap1Range = Workbooks("restcompfirm.xls").Worksheets("Sheet1").Range("AP1")
set bm1Range = Workbooks("restcompfirm.xls").Worksheets("Sheet1").Range("BM1")
Dim country(), roe(), iCap() As String
Dim i As Integer
totalRows = 3357
redim country(totalRows)
redim roe(totalRows)
redim iCap(totalRows)
For i = 0 To (totalRows - 1)
rowNum = rowNum + 1
roe(rowsWithoutNA) = ap1Range.Offset(rowNum, 0).Text
iCap(rowsWithoutNA) = bm1Range.Offset(rowNum, 0).Text
if (WorksheetFunction.IsNA(roe(rowNum)) _
OR WorksheetFunction.IsNA(iCap(rowNum))) = False Then
' use the following condition, if NA is written in text
'if (trim(roe(rowNum)) = "NA" OR trim(iCap(rowNum)) = "NA") Then
country(rowsWithoutNA) = c1Range.Offset(rowNum, 0)
rowsWithoutNA = rowsWithoutNA + 1
end if
Next i
redim preserve country(rowsWithoutNA )
redim preserve roe(rowsWithoutNA )
redim preserve iCap(rowsWithoutNA )
end sub
I wouldn't even include the "NA" in the first place when building the arrays. Here's your code, but changed to not include "NA".
Sub group_data()
Dim country() As String
ReDim country(0)
Dim roe() As String
ReDim roe(0)
Dim iCap() As String
ReDim iCap(0)
Dim i As Integer
Dim increment1, increment2, increment3 As Integer
increment1 = 0
increment2 = 0
increment3 = 0
For i = 1 To 3357
If Not Workbooks("restcompfirm.xls").Worksheets("Sheet1").Range("C1").Offset(i, 0) = "NA" Then
ReDim Preserve country(UBound(country) + 1)
country(increment1) = Workbooks("restcompfirm.xls").Worksheets("Sheet1").Range("C1").Offset(i, 0)
increment1 = increment1 + 1
End If
If Not Workbooks("restcompfirm.xls").Worksheets("Sheet1").Range("AP1").Offset(i, 0) = "NA" Then
ReDim Preserve roe(UBound(roe) + 1)
roe(increment2) = Workbooks("restcompfirm.xls").Worksheets("Sheet1").Range("AP1").Offset(i, 0)
increment2 = increment2 + 1
End If
If Not Workbooks("restcompfirm.xls").Worksheets("Sheet1").Range("BM1").Offset(i, 0) = "NA" Then
ReDim Preserve iCap(UBound(iCap) + 1)
iCap(increment3) = Workbooks("restcompfirm.xls").Worksheets("Sheet1").Range("BM1").Offset(i, 0)
increment3 = increment3 + 1
End If
Next i
End Sub
Just to be clear, I am assuming you have a list of countries in Range C1 and then associated roe and iCap values in ranges AP1 and BM1. The issue that some of the roe and iCap entires are missing and have been entered as 'NA'. You would like to create arrays that contain only countries where there is both an roe and iCap value.
Firstly, using Redim Preserve is an 'expensive' operation and will impact efficiency of code.
Secondly, as an aside, using syntax as in your code (below) will only set the final variable to String. The first two will be created as variable type Variant:
Dim country(), roe(), iCap() As String
This code should be written as:
Dim country() as String, roe() as String, iCap() As String
In terms of your issue, my approach would be as follows:
Sub FillArrays()
'Define arrays
Dim countryArray() As String, roeArray() As Variant, iCapArray() As Variant
'Get total number of countries
Dim totalRows As Long
totalRows = Workbooks("restcompfirm.xls").Worksheets("Sheet1").Range("C1").End(xlDown).Row
'Define array size based on totalRows
ReDim countryArray(totalRows - 1)
ReDim roeArray(totalRows - 1)
ReDim iCapArray(totalRows - 1)
'Define missing data text
Dim missingData As String
missingData = "NA"
Dim iArray As Long
iArray = 0
With Workbooks("restcompfirm.xls").Worksheets("Sheet1")
'Loop through each row and check if either roe or iCap are set to 'NA'
For cl = 1 To totalRows
If Trim(.Range("AP" & cl)) <> missingData Then
If Trim(.Range("BM" & cl)) <> missingData Then
countryArray(iArray) = .Range("C" & cl)
roeArray(iArray) = .Range("AP" & cl)
iCapArray(iArray) = .Range("BM" & cl)
iArray = iArray + 1
End If
End If
Next cl
End With
End Sub
Hope this helps.

Resources