Split string into matrix vba - vba

I have 3 informations on a row and I can have multiple row selected. So what I'm looking for is a way to split a first time each row into an array.
That's what I'm doing here.
line = Split(msg, ",")
Then I want to for every line to split info to obtain a matrix with first identifer the line and the second is the info
ReDim pro(Ubound(line),3)
For i = 0 To Ubound(line)
pro(i) = Split(ligne(i), "/")
Next
But It throw me a mismatch error so I don't know how to do it
for example :
I have this
msg1/1250/Description,msg2/1500/Description2,msg3,45656,Desctiption3
And finally have this :
pro(0,0) = msg1
pro(0,1) = 1250
pro (1,1) = 1500
etc ...
Thank you

Not optimal in any way, but it should give you a start:
Dim RowCount As Integer
Dim i As Integer
Dim j As Integer
Dim x As Variant
Dim y As Variant
Line = "msg1/1250/Description,msg2/1500/Description2,msg3/45656/Desctiption3"
RowCount = UBound(Split(Line, ",")) + 1
ReDim pro(RowCount, 3)
For Each x In Split(Line, ",")
j = 0
For Each y In Split(x, "/")
pro(i, j) = y
j = j + 1
Next y
i = i + 1
Next x

What you have initially as pro is called a "jagged array". You can use a "double-transpose" to transform it into a 2D array. But beware that it needs that all the "line arrays" be of the same size:
Function toMatrix(msg as string)
Dim line: line = Split(msg, ",")
ReDim pro(UBound(line))
Dim i As Long
For i = 0 To UBound(line)
pro(i) = Split(line(i), "/")
Next
' transform array of arrays into a 2D array.
toMatrix = Application.Transpose(Application.Transpose(pro))
End Function
Sub Test
Dim msg As String
msg = "msg1/1250/Description,msg2/1500/Description2,msg3/45656/Desctiption3"
Dim ar
ar = toMatrix(msg) ' ar is now a 2D array
End Sub

This is how I did it:
Option Explicit
Public Sub TestMe()
Dim strInput As String
Dim arrVals As Variant
Dim arrVar As Variant
Dim arrVar2 As Variant
Dim arrResult As Variant
Dim lngCount As Long: lngCount = 0
strInput = "msg1/1250/Description,msg2/1500/Description2,msg3/45656/Desctiption3"
arrVals = Split(strInput, ",")
ReDim arrResult(UBound(arrVals), 1)
For Each arrVar In arrVals
arrVar2 = Split(arrVar, "/")
arrResult(lngCount, 0) = arrVar2(0)
arrResult(lngCount, 1) = arrVar2(1)
lngCount = lngCount + 1
Next arrVar
End Sub
That's the result:
As far as I did not see that you need a DescriptionN I have skipped it.

Related

How to convert array from (x,y)(z) dimensions into (x,y) dimensions?

I am working with Bloomberg's API in VBA and I want to be able to take in the arrays that the API gives out from requesting historical data and put it into a table that has field names. However, the array that the API gives me is given in this format: (x,y)(Z) but I cannot use that for inserting into a table. I also want to be able to add another piece of data into the array while I convert from one form to another
I have tried just going through the Bloomberg array and replacing each element in a different array, but the main issues I have are not being able to know how big I need the array to be and how I am going to loop through the bloomberg API without going out of index and getting an error. I have tried using Ubound, but it does not work the way I have intended.
This is the code I have tried using to convert my array and then insert it. It just puts in blank values and does not put in anything into the table
Sub mWriteToTable(vTableName As String, ByVal vArray As Variant, vCUSIPS As Variant, vFields As Variant)
On Error GoTo ErrorHandler
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim x As Long, y As Long
Dim TEST As String
Dim DataArray() As Variant
Set db = CurrentDb
Set rs = db.OpenRecordset(vTableName, dbOpenDynaset, dbSeeChanges)
TEST = ""
Dim xBound As Integer, yBound As Integer, ThirdBound As Integer, fieldcount As Integer, NewBoundY As Integer, Z As Integer
Dim Boundarynum As Integer
Boundarynum = 0
Dim Boundarynum1 As Integer
Boundarynum1 = 0
fieldcount = UBound(vFields, 1) + 1
xBound = UBound(vArray, 1)
yBound = UBound(vArray, 2)
NewBoundY = fieldcount * (fieldcount + 1)
ReDim DataArray(0 To 20, 0 To (xBound + 1))
'using a static size for the array for now. Will try and make it the same size as the bloomberg array
'TRANSFORMING ARRAY FROM BLOOMBERG
For x = 0 To xBound
For y = 0 To NewBoundY
For Boundarynum1 = 0 To yBound
On Error Resume Next
DataArray(Boundarynum, Boundarynum1) = vArray(x, y)(Boundarynum1)
Next
Boundarynum = Boundarynum + 1
Next
Next
'TRANSFORMING ARRAY FROM BLOOMBERG
'set CUSIP in array
y = 0
Dim counter As Integer
counter = 0
For Z = 0 To 20
If DataArray(Z, 0) = "" Then
Debug.Print ("")
counter = 1
ElseIf counter = 1 And DataArray(Z, 0) <> "" Then
y = y + 1
DataArray(Z, 3) = vCUSIPS(y)
counter = 0
Else
DataArray(Z, 3) = vCUSIPS(y)
End If
Next
'set CUSIP in array
For x = 0 To 20
With rs
.AddNew
For y = 0 To yBound
' On Error GoTo Line1
' If vArray(x, y) = "NA" Then
' TEST = "This is a test"
' End If
'Line1:
.fields(y) = DataArray(x, y)
Next
.Update
End With
Next
'Call fImmediateWindow(vArray)
ErrorHandler:
If Err.Number <> 0 Then
Dim vMsg As String
vMsg = "Error # " & Str(Err.Number) & " was generated by " & Err.Source & Chr(13) & "Error Line: " & Erl & Chr(13) & Err.Description
MsgBox vMsg, , "Error", Err.HelpFile, Err.HelpContext
End If
rs.Close
Set rs = Nothing
db.Close
Set db = Nothing
End Sub
'''
This is the way the Bloomberg Array looks when I get it. I am unsure of how to really work around this. The array from the program above just becomes blank.
Each element of the Bloomberg array is returning 2 sets of data. The key is to have your array have double the number of elements of the top level Bloomberg array.
Sub ConvertBloombergTestData()
Dim r As Variant
r = getBloombergTestData
Dim Values As Variant
Dim n As Long
Dim j As Long
Dim Item
ReDim Values(1 To (UBound(r) + 1) * 2, 1 To 2)
For n = LBound(r) To UBound(r)
j = j + 1
Item = r(n, 0)
Values(j, 1) = Item(0)
Values(j, 2) = Item(1)
Item = r(n, 1)
j = j + 1
Values(j, 1) = Item(0)
Values(j, 2) = Item(1)
Next
End Sub
Not knowing the the array nesting but knowing that we are returning pairs of data, we could add all the data to a collection and create our array bu iterating over the collection.
Sub Test()
Dim r As Variant, Values As Variant
r = getBloombergTestData
Values = ConvertBloombergArrayTo2d(r)
End Sub
Function ConvertBloombergArrayTo2d(BloombergArray)
Dim Map As New Collection
FlattenArray Map, BloombergArray
Dim Results As Variant
ReDim Results(1 To Map.Count / 2, 1 To 2)
Dim n As Long, j As Long
For n = 1 To Map.Count Step 2
j = j + 1
Results(j, 1) = Map.Item(n)
Results(j, 2) = Map.Item(n + 1)
Next
ConvertBloombergArrayTo2d = Results
End Function
Sub FlattenArray(Map As Collection, Element As Variant)
If Right(TypeName(Element), 2) = "()" Then
Dim Item
For Each Item In Element
FlattenArray Map, Item
Next
Else
Map.Add Element
End If
End Sub

want to put inputs of a text file into a multidimensional array and retrieve entries based on array(i,j)

So i have a text file which has a number of lines and each line has entries separated by delimiters. I have managed to break the data down and put them into a multi-dimensional array, please see code below.
each row has differing amount of entries separated by delimeters
Public Sub testarr()
Dim i As Integer
Dim j As Integer
Dim iFile As Integer
Dim TotalRows() As String
Dim TotalColumns() As String
Dim sData As String
Dim MyArray() As String
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Const forReading = 1
filepath = "C:\test1"
Set F = fso.OpenTextFile(filepath, forReading) 'open file for reading
y = 1
n = 5 'i've called a function to retrieve num of lines
'breaking into separate lines
For i = 1 To n
strContents = F.readline
strconts = strconts & vbCrLf & strContents
Debug.Print strconts
Next
Debug.Print strconts
TotalRows() = Split(strconts, vbNewLine)
'ReDim Preserve TotalRows(y)
'TotalRows = Split(sData, vbCrLf)
For y = 1 To 5
Debug.Print TotalRows(y)
Next y
'trying to separate each roads by the delimeters
For x = 1 To n
For y = 1 To 5
TotalColumns(x) = Split(TotalRows(y), "|")
Next y
Next x
above splits the rows but each line is the same
For i = LBound(TotalRows) To UBound(TotalRows)
For j = LBound(TotalColumns) To UBound(TotalColumns)
MyArray(i, j) = TotalColumns(j)
Debug.Print MyArray(i, j)
Next
Next
End Sub
maybe there is another suggestion to do this. I just want to be able to retrieve entries of a particular line and column array( line 2, column 3). But each line will have a different number of entries so i do not want to define the number of columns but will define the number of lines.
You can use a "jagged" array:
'...
TotalRows() = Split(strconts, vbNewLine)
For x = lbound(TotalRows) to unbound(TotalRows)
TotalRows(x) = Split(TotalRows(x), "|")
Next x
'....
Each "row" is now an array, so it would be something like:
blah = TotalRows(2)(2)
to get the third item on the third row. Obviously you'd need some bounds checking when accessing each sub-array.
edited after OP's clarification
may this is the code you are after
Option Explicit
Public Sub testarr()
Const forReading = 1
Dim filepath As String
filepath = "C:\test1"
Dim strconts As String
With CreateObject("Scripting.FileSystemObject") 'create and reference FilSystemObject object
With .OpenTextFile(filepath, forReading) 'open file for reading and reference it
'breaking into separate lines
Do While .AtEndOfStream <> True 'read the file till its last line
strconts = strconts & .ReadLine & vbCrLf
Loop
.Close 'close referenced file
End With
End With
Dim TotalRows As Variant
TotalRows = Split(strconts, vbNewLine)
ReDim TotalColumns(LBound(TotalRows) To UBound(TotalRows)) As Variant 'dim your TotalColumns array with same rows number as TotalRows
Dim i As Integer, nCols As Long, nColsMax As Long
For i = LBound(TotalRows) To UBound(TotalRows)
TotalColumns(i) = Split(TotalRows(i), "|") 'have each TotalColumn element store an array
nCols = UBound(TotalColumns) - LBound(TotalColumns)
If nCols > nColsMax Then nColsMax = nCols 'store maximum number of columns across TotalColumns arrays
Next
ReDim MyArray(LBound(TotalColumns) To UBound(TotalColumns), 0 To nColsMax) As String 'size MyArray to the same rows number of TotalColumns and the maximum number of columns
Dim j As Integer
For i = LBound(TotalColumns) To UBound(TotalColumns)
For j = LBound(TotalColumns(i)) To UBound(TotalColumns(i))
MyArray(i, j) = TotalColumns(i)(j)
Debug.Print MyArray(i, j)
Next
Next
End Sub
of course this code can be collapsed further, but that is something you can do afterwards

Array - Subscript out of range in VBA

I am trying to store the values inside an array. I am facing a problem it says subscript out of range.
This is the code,
Sub Trial()
Dim HeaderArray() As Variant
Dim HeaderValue As String
Dim j As Long
Dim i as Long
set wk = Activeworkbook
lastrow_header_Config = Wk.Sheets("Config").Cells(Rows.Count, "W").End(xlUp).Row
j = 1
For i = 2 To lastrow_header_Config
HeaderValue = Wk.Sheets("Config").Range("W" & i).Value
If HeaderValue <> "" Then
HeaderArray(j - 1) = HeaderValue // Subscript out of range error
j = j + 1
End If
Next
End Sub
What is the mistake I am making. Kindly advise.
You need to declare the size of the array before trying to put data in it. Use COUNTA to find the number of cells with data in your range:
Sub Trial()
Dim HeaderArray() As Variant
Dim HeaderValue As String
Dim lastrow_Header_Config As Long
Dim j As Long
Dim i As Long
Set Wk = ActiveWorkbook
lastrow_Header_Config = Wk.Sheets("Config").Cells(Rows.Count, "W").End(xlUp).Row
ReDim HeaderArray(Application.WorksheetFunction.CountA(Wk.Sheets("Config").Range("W2:W" & lastrow_Header_Config))-1) As Variant
j = 0
For i = 2 To lastrow_Header_Config
HeaderValue = Wk.Sheets("Config").Range("W" & i).Value
If HeaderValue <> "" Then
HeaderArray(j) = HeaderValue
j = j + 1
End If
Next
End Sub
try this and see how it works for you
pay close attention to the ReDim HeaderArray(j) line and the ReDim Preserve HeaderArray(j) lines
Sub Trial()
Dim HeaderArray() As Variant
Dim HeaderValue As String
Dim j As Long
Dim i As Long
Set Wk = ActiveWorkbook
lastrow_header_Config = Wk.Sheets("Config").Cells(Rows.Count, "W").End(xlUp).Row
j = 1
ReDim HeaderArray(j) '<============= initialize your array length
For i = 2 To lastrow_header_Config
HeaderValue = Wk.Sheets("Config").Range("W" & i).Value
If HeaderValue <> "" Then
ReDim Preserve HeaderArray(j) '<================= adjust your array length to accomodate the additional info
HeaderArray(j - 1) = HeaderValue '// Subscript out of range error
j = j + 1
End If
Next
End Sub
Also you might want to read up on using the option keyword. Arrays by default have the first data point at index 0 so for example array(1) creates an array that has 1 data point, however to reference that data point you would use array(0). if you wanted the first data point in the array to be referenced using array(1), then you would use the Option Base 1 keyword at the very top of your module.
On the first pass, j = 1. Therefore you try to set HeaderArray(0) a value, while HeaderArray is probably 1 based.
You can eventually use Option Base 0, or explicitely Redim HeaderArray(0 to 10) (or whatever value you need)

Pulling Key values from VBA dictionary

I have identified unique values in a list of data by the method I have abbreviated below:
Dim dictionary as scripting.dictionary
Dim data() as String
Dim dataSize as Integer
Dim j as integer
Dim v as variant
DataSize = myRange.Rows.Count
Redim data(dataSize)
For j = 1 to UBound(data)
data(j) = myRange.Cells(j,1).Value
dictionary(data(j)) = 1
Next j
This should be storing the unique values from myRange as the Key values. However, I can't seem to figure out how to access the values. I have tried the following:
For each v in dictionary.Keys()
myVar = v
'dostuff to myVar
next v
and
For each v in dictionary.Keys()
myVar = dictionary.Keys(v)
'dostuff to myVar
next v
but neither works. What am I missing?
Add Set dictionary = New dictionary and then you can loop through:
Sub t()
Dim dictionary As Scripting.dictionary
Dim data() As String
Dim dataSize As Integer
Dim j As Integer
Dim v As Variant
dataSize = myRange.Rows.Count
Set dictionary = New dictionary
ReDim data(dataSize)
For j = 1 To UBound(data)
data(j) = myRange.Cells(j, 1).Value
dictionary(data(j)) = 1
Next j
Dim i As Long
For i = 0 To dictionary.Count - 1
Debug.Print dictionary.Keys()(i) & " " & dictionary.Items()(i)
Next i
End Sub

VBA function creating a layer of 0 around the output range

I've got the following Macro and Function working, but the pasted result has a layer of zeroes in the left side and top of the result. hope you guys can figure out the error in my code. I am to believe the error is in the function:
Sub AutoCovariance()
Dim DataRange As Range
Dim VarCovarOutPutRange As Range
Dim NumberOfReturns As Long
Dim NumberOfStocks As Long
Dim ArrayColumnsCounter As Double
Dim ArrayRowsCounter As Double
Dim ReturnsArray() As Double
Dim DataReturns() As Variant
Dim DataRowCounter As Long
Dim DataColumnCounter As Long
Dim Stock As Long
Dim dAutoCoVar() As Double
Set DataRange = ThisWorkbook.Worksheets(Sheet1.Name).ListObjects("DataTable").DataBodyRange
NumberOfReturns = ThisWorkbook.Worksheets(Sheet1.Name).ListObjects("DataTable").DataBodyRange.Rows.Count
NumberOfStocks = ThisWorkbook.Worksheets(Sheet1.Name).ListObjects("DataTable").Range.Columns.Count
ArrayColumnsCounter = 0
ArrayRowsCounter = 0
ReDim Preserve ReturnsArray(10, 1)
' Creating returns array
For DataColumnCounter = 1 To NumberOfStocks
ArrayRowsCounter = ArrayRowsCounter + 1
For DataRowCounter = 1 To NumberOfReturns
ArrayColumnsCounter = ArrayColumnsCounter + 1
ReDim Preserve ReturnsArray(NumberOfStocks, ArrayColumnsCounter)
For Stock = 1 To NumberOfStocks
ReturnsArray(Stock, ArrayColumnsCounter) = DataRange(DataRowCounter, Stock).Value
Next Stock
Next DataRowCounter
ArrayColumnsCounter = ArrayColumnsCounter - 100
Next DataColumnCounter
' Transfer ReturnsArray Data to DataReturns
ReDim DataReturns(NumberOfReturns, NumberOfStocks)
DataReturns = Application.WorksheetFunction.Transpose(ReturnsArray)
' calculate the autocovariance matrix
dAutoCoVar = Autocovar(DataReturns)
' write to the worksheet, for debug
Set VarCovarOutPutRange = ThisWorkbook.Worksheets(Sheet1.Name).Range(Cells(1, NumberOfStocks + 2), Cells(NumberOfStocks, NumberOfStocks * 2 + 2))
VarCovarOutPutRange.Value = dAutoCoVar
End Sub
And the Function
Function Autocovar(DataReturns() As Variant) As Double()
Dim dArrResult() As Double
Dim j As Long, k As Long
' redim the result array as a square array.
ReDim dArrResult(1 To UBound(DataReturns, 2), 1 To UBound(DataReturns, 2))
' calculate the autocovariance matrix
For j = 1 To UBound(DataReturns, 2)
For k = 1 To UBound(DataReturns, 2)
With Application.WorksheetFunction
dArrResult(j, k) = .Covariance_S(.Index(DataReturns, 0, j), .Index(DataReturns, 0, k))
End With
Next k
Next j
Autocovar = dArrResult
End Function
The problem sounds typical for wrong array indices.
Your array operations all assume that the first index is 1. But by default, if you ReDim an array like this:
ReDim DataReturns(NumberOfReturns, NumberOfStocks)
the indices will start at 0.
Try adding this line at the beginning of your module:
Option Base 1
This sets the first index of all arrays not explicitely declared as Dim ar(x to y) to a base index of 1.