I have this following subroutine In Access VBA:
Sub SampleReadCurve()
Dim rs As Recordset
Dim iRow As Long, iField As Long
Dim strSQL As String
Dim CurveID As Long
Dim MarkRunID As Long
Dim MaxOfMarkAsofDate As Date
Dim userdate As String
CurveID = 15
Dim I As Integer
Dim x As Date
userdate = InputBox("Please Enter the Date (mm/dd/yyyy)")
x = userdate
For I = 0 To 150
MaxOfMarkAsofDate = x - I
strSQL = "SELECT * FROM VolatilityOutput WHERE CurveID=" & CurveID & " AND MaxOfMarkAsofDate=#" & MaxOfMarkAsofDate & "# ORDER BY MaxOfMarkasOfDate, MaturityDate"
Set rs = CurrentDb.OpenRecordset(strSQL, Type:=dbOpenDynaset, Options:=dbSeeChanges)
If rs.RecordCount <> 0 Then
rs.MoveFirst
rs.MoveLast
Dim BucketTermAmt As Long
Dim BucketTermUnit As String
Dim BucketDate As Date
Dim MarkAsOfDate As Date
Dim InterpRate As Double
BucketTermAmt = 3
BucketTermUnit = "m"
BucketDate = DateAdd(BucketTermUnit, BucketTermAmt, MaxOfMarkAsofDate)
InterpRate = CurveInterpolateRecordset(rs, BucketDate)
Debug.Print BucketDate, InterpRate
End If
Next I
End Function
This subroutine put outs a 2x2 list of 76 numbers, consisting of a date and an associated rate. I want to store this list of values as a Collection, so that I can use it as an input in another function. Is it possible to use collections to do this? What would be the appropriate syntax?
I agree with comments that a data dictionary is probably the way to go. The reason is that with a dictionary you can actually loop through the keys if needed. You will need to add a reference to the Microsoft Scripting Runtime. Here is a brief example:
Public Function a()
Dim dRates As New Scripting.Dictionary
Dim key As Variant
dRates.Add #1/1/2016#, 1
dRates.Add #2/1/2016#, 1.5
dRates.Add #3/1/2016#, 2
'You can either access the rate directly with the key:
Debug.Print dRates(#2/1/2016#)
'Or you can loop through the keys/values
For Each key in dRates.Keys
Debug.Print key & " - " & dRates(key)
Next
'Or, you can pass the entire collection to a function
Call b(dRates)
End Function
Public Function b(d As Scripting.Dictionary)
For Each key In d.Keys
Debug.Print key & " - " & d(key)
Next
End Function
This will provide the following output:
1.5
1/1/2016 - 1
2/1/2016 - 1.5
3/1/2016 - 2
1/1/2016 - 1
2/1/2016 - 1.5
3/1/2016 - 2
Related
I'm quite new to VBA (2 months in) and I'm trying to add three variables to a scripting dictionary in order to reformat an Excel Table and I am running into an error.
I have tried to add three variables by
countrydict.Add country, data, time
But I get an error message
Run-time error '450':
Wrong number of arguments or invalid property assignment
However it works if I write
countrydict.Add country, data 'or
countrydict.Add country, time
Dim lastrow As Long
Dim iter As Long
Dim diter As Long
Dim countrydict As Object
Dim country As String
Dim data As String
Dim time As String
Dim key As Variant
Dim i As Long
Const StartRow As Byte = 2
lastrow = Range("A" & StartRow).End(xlDown).Row
Set countrydict = CreateObject("Scripting.Dictionary")
Dim diter2 As Long, arr, arr2
With ActiveSheet
For iter = 2 To lastrow
country = Trim(.Cells(iter, 1).Value) '<<<<<
data = Trim(.Cells(iter, 2).Value) '<<<<<
time = Trim(.Cells(iter, 3).Text) '<<<<<
If countrydict.Exists(country) Then
If Not InStr(1, countrydict(country), data) > 0 Then
countrydict(country) = countrydict(country) & _
"|" & data & "/" & time
End If
Else
countrydict.Add country, data, time '<<<<<<<
End If
Next
iter = 2
For Each key In countrydict
.Cells(iter, 1).Value = key & ":"
.Cells(iter, 1).Font.Bold = True
.Cells(iter, 1).Font.ColorIndex = 30
iter = iter + 1
arr = Split(countrydict(key), "|")
For diter = 0 To UBound(arr)
arr2 = Split(arr(diter), "/")
.Cells(iter, 1).Value = arr2(0)
.Cells(iter, 2).Value = arr2(1)
Next diter
Next key
End With
End Sub
The expected result is to reformat a table in this format
"A" "B" "C"
EU Sales 10:00
EU Tax 12:00
USA Sales 09:00
USA Tax 10:00
Into this format
EU:
Sales 10:00
Tax 12:00
USA:
Sales 09:00
Tax 10:00
Many thanks for any help. I've been struggeling with this problem for days...
Another possibility is to create a new class to store your data. Store your data in an instance of this class and then pass this object to your dictionary.
This way you could event extend the class to return other stuff, for example all values as a combined string etc... Using public properties you can even set up input validation and what not, but this is probably more than what is needed right now.
I kept the "Class" to the absolute minimum, normally public variables in classes are bad, but since we only use it as custom datatype this does not matter.
Edit: I updatet the class a bit to show some more functionality, but I leave the old one here as an example.
Standard Module "Module1":
Option Explicit
Sub fillDict()
Dim adict As Scripting.Dictionary
Set adict = New Dictionary
Dim info As myRegionData
Dim iter As Long
For iter = 0 To 10
Set info = New myRegionData
info.Region = "someRegion" & iter
info.data = "someData" & iter
info.Time = "someTime" & iter
adict.Add info.Region, info
Next iter
Dim returnInfo As myRegionData
Set returnInfo = adict.Item("someRegion1")
With returnInfo
Debug.Print .Region, .data, .Time 'someRegion1 someData1 someTime1
Debug.Print .fullSentence 'At someTime1 I was in someRegion1 and did someData1
End With
End Sub
Class Module (simple) "myRegionData":
Option Explicit
Public Region As String
Public data As String
Public Time As String
Class Module (extended) "myRegionData":
Option Explicit
Private Type TmyRegionData
'More about this structure:
'https://rubberduckvba.wordpress.com/2018/04/25/private-this-as-tsomething/
Region As String
data As String
Time As String
End Type
Private this As TmyRegionData
Public Property Get Region() As String
Region = this.Region
End Property
Public Property Let Region(value As String)
this.Region = value
End Property
Public Property Get data() As String
data = this.data
End Property
Public Property Let data(value As String)
this.data = value
End Property
Public Property Get Time() As String
Time = this.Time
End Property
Public Property Let Time(value As String)
this.Time = value
End Property
Public Function getFullSentence() As String
getFullSentence = "At " & Time & " I was in " & Region & " and did " & data
End Function
VBA has a dictionary structure. Dictionary is an object, and it can be referenced either with early binding (likeSet countrydict = CreateObject("Scripting.Dictionary")) or with a late binding, referring to Microsoft Scripting Runtime (In VBEditor>Extras>Libraries):
The latter has the advantage, that it is a bit faster and pressing Ctrl+space one would see the Intelli-Sense:
Concerning the question with multiple variables to a dictionary, then an array with those is a possibility:
Sub MyDictionary()
Dim myDict As New Scripting.Dictionary
If Not myDict.Exists("Slim") Then
Debug.Print "Adding Slim"
myDict.Add "Slim", Array("Eminem", "has", "a", "daughter!")
End If
If Not myDict.Exists("Barcelona") Then
Debug.Print "Adding Barcelona"
myDict.Add "Barcelona", Array("I", "have", "been there", 2018)
End If
If Not myDict.Exists("Barcelona") Then
myDict.Add "Barcelona", Array("I", "have", "been there", 2018)
Else
Debug.Print "Barcelona already exists!"
End If
'Keys
Dim key As Variant
For Each key In myDict.Keys
Debug.Print "--------------"
Debug.Print "Key -> "; key
Dim arrItem As Variant
For Each arrItem In myDict(key)
Debug.Print arrItem
Next
Next key
End Sub
This is the result of the code:
Adding Slim
Adding Barcelona
Barcelona already exists!
--------------
Key -> Slim
Eminem
has
a
daughter!
--------------
Key -> Barcelona
I
have
been there
2018
If the value of the dictionary is not an array, e.g. adding somewhere myDict.Add "notArray", 124, an error would pop up once it tries to print the array. This can be avoided with the usage of IsArray built-in function.
i have a comma delimited text file as follows
RLGAcct#,PAYMENT_AMOUNT,TRANSACTION_DATE,CONSUMER_NAME,CONSUMER_ADD_STREET,CONSUMER_ADD_CSZ,CONSUMER_PHONE,CONSUMER_EMAIL,LAST_FOUR
ZTEST01,50.00,11/15/2018,ROBERT R SMITH,12345 SOME STREET,60046,,adam#adamparks.com,2224
ZTEST02,100.00,11/15/2018,ROBERT JONES,5215 OLD ORCHARD RD,60077,,adam#adamparks.com,2223
ZTEST03,75.00,11/15/2018,JAMES B MCDONALD,4522 N CENTRAL PARK AVE APT 2,60625,,adam#adamparks.com,2222
ZTEST04,80.00,11/15/2018,JOHN Q DOE,919 W 33RD PL 2ND FL,60608,,adam#adamparks.com,2221
ZTEST05,60.00,11/15/2018,SAMANTHAN STEVENSON,123 MAIN ST,60610,,adam#adamparks.com,2220
I need to export this to excel so that each value between a comma is inserted into a column in excel
So
ZTEST01 is in A1,
50.00 is in B1
11/15/2018 in C1 ...
The thing is i need each row to be inserted into a newly created excel worksheet.
The code i have is as follows:
Dim xlApp As New Excel.Application
Dim xlWorkbook As Excel.Workbook
Dim xlWorksheet As Excel.Worksheet
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
'xlWorkbook = xlApp.workboos.Add() using this later once i have the parsing figured out
Dim columns As New List(Of String)
Dim ccPayment = "C:\Users\XBorja.RESURGENCE\Downloads\Payments_Credit.txt"
Using MyReader As New Microsoft.VisualBasic.FileIO.TextFieldParser(ccPayment)
MyReader.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited
MyReader.Delimiters = New String() {","}
Dim currentRow As String()
'Loop through all of the fields in the file.
'If any lines are corrupt, report an error and continue parsing.
While Not MyReader.EndOfData
Try
currentRow = MyReader.ReadFields()
' Include code here to handle the row.
For Each r In currentRow
columns.Add(r)
C
Next r
Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
MsgBox("Line " & ex.Message & " is invalid. Skipping")
End Try
End While
'Dim index0 = columns(0)
'Dim index1 = columns(1)
'Dim index2 = columns(3)
'Dim index3 = columns(3)
'Dim index4 = columns(4)
'Dim index5 = columns(5)
'Dim index6 = columns(6)
'Dim index7 = columns(7)
'Dim index8 = columns(8)
'Console.WriteLine(index0 & index1 & index2 & index3 & index4 & index5 & index6 & index7 & index8)
End Using
For Each r In columns
Console.WriteLine(r)
Next
end sub
As you can see I was trying to see if i could index these so that i could possibly equate each one to a cell in excel.
The other problem is that this text file changes daily. The columns are always set (9 columns) but the rows change dynamically daily based on how many transactions we get.
I would recommend using the EPPlus package which is available via NuGet. It removes the COM challenges of working with Excel and works by reading and writing the XLSX spreadsheet files.
The following sample does what you where asking:
Private Sub btnStackOverflowQuestion_Click(sender As Object, e As EventArgs) Handles btnStackOverflowQuestion.Click
Dim ccPayment As String = "C:\temp\so.csv"
Using pkg As New ExcelPackage()
Using MyReader As New Microsoft.VisualBasic.FileIO.TextFieldParser(ccPayment)
MyReader.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited
MyReader.Delimiters = New String() {","}
Dim sheetCount As Integer
While Not MyReader.EndOfData
sheetCount += 1
Dim newSheet As ExcelWorksheet = pkg.Workbook.Worksheets.Add($"Sheet{sheetCount}")
Try
Dim currentRow As String() = MyReader.ReadFields()
Dim columnCount As Integer = 0
For Each r In currentRow
columnCount += 1
newSheet.Cells(1, columnCount).Value = r
Next r
Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
MsgBox("Line " & ex.Message & " is invalid. Skipping")
End Try
End While
End Using
Dim fi As New FileInfo("C:\temp\so.xlsx")
pkg.SaveAs(fi)
End Using
End Sub
I have a function that prints the time to an excel in 5 lots each. I have a function that first stores time in collection object and then converts it to an array & finally this function would call another function to populate the array in to excel.
Below my function for your reference.
Public daytime_store As New Collection
Public daytime_tm As New Collection
Public daytime_store_cnt As New Collection
Option Explicit
Function n50_store_day()
Dim I_day As Date, Currtime_cutoff As Date, daytime_store_arr As Variant, daytime_tm_arr As Variant, lx As Integer, ly As Integer
I_day = Format(Now(), "hh:mm:ss")
daytime_store.Add I_day
If daytime_store.Count = 5 Then
daytime_store_cnt.Add 5
ly = daytime_store_cnt.Count
If ly = 1 Then lx = 1
If ly > 1 Then lx = ((ly - 1) * 5) + 1
daytime_store_arr = CollectionToArray(daytime_store)
Set daytime_store = New Collection
Call varitoxl(daytime_store_arr, lx)
End If
End Function
This is working perfectly if i run the function from F5 but showing wrong data type error if called from a spread sheet. Would anyone guide on this.
Also below function of varitoxl:
Function varitoxl(dlr As Variant, yz As Integer) As Variant
Dim strFilename As String: strFilename = "C:\Users\Acer\Desktop\n50imp\book1.xlsx"
Dim wb As Workbook
Set wb = Workbooks.Open(Filename:=strFilename)
Dim ws As Worksheet
Set ws = wb.Worksheets("sheet1")
Debug.Print 1
ws.Cells(yz, 1).Resize(5, 1) = dlr
Debug.Print 2
ActiveWorkbook.Close SaveChanges:=True
End Function
I am currently looking in a string for a particular value and creating a new string from it. Was wondering if there is any efficient code to do it?
Example:
I have string as:
ISSCD = "ISSUE1; ISSUE2; ISSUE3; ISSUE1; ISSUE3; ISSUE10; ISSUE12; ISSUE2; ISSUE18; ISSUE18; ISSUE1;
but want string as:
NEWISSCD = "ISSUE1; ISSUE2; ISSUE3; ISSUE10; ISSUE12; ISSUE18; "
Here is the code I am using:
Sub test()
Dim ISSCD, NEWISSCD as String
NEWISSCD = ""
If InStr(ISSCD, "ISSUE1;") > 0 Then NEWISSCD = NEWISSCD & "ISSUE1; "
If InStr(ISSCD, "ISSUE2;") > 0 Then NEWISSCD = NEWISSCD & "ISSUE2; "
'...
If InStr(ISSCD, "ISSUE50;") > 0 Then NEWISSCD = NEWISSCD & "ISSUE50; "
End Sub
You can use a dictionary for this purpose. By using dictionary, you can also count have many times your ISSUE# occurs in your original list.
Please see this:
Sub test()
Dim ISSCD()
Dim i As Long
Dim dict As Object
Dim key As Variant
Set dict = CreateObject("Scripting.Dictionary")
ISSCD = Array("ISSUE1", "ISSUE2", "ISSUE3", "ISSUE1", "ISSUE3", "ISSUE10", "ISSUE12", "ISSUE2", "ISSUE18", "ISSUE18", "ISSUE1")
For Each Item In ISSCD
If dict.Exists(Item) Then
dict(Item) = dict(Item) + 1
Else
dict.Add Item, 1
End If
Next Item
For Each key In dict.Keys
Debug.Print key, dict(key)
Next key
End Sub
Following is the statement
Performance;#Recruiting;#Culture and values;#Community Involvement &
Volunteerism;/Talent Development;#Workplace
I want each value present after the ;# sign to be paste in a new cell? How do i do it?
I've not used VBA for some time, but this should get you started at least:
Private Sub ProcessStr()
Dim strTest As String
Dim strArray() As String
Dim i As Integer
strTest = "YOUR STRING"
strArray = Split(strTest, ";")
For i = LBound(strArray) To UBound(strArray)
// REMOVE # SIGN HERE ?
// DO SOMETHING WITH THE VALUES
// strArray(i) - CONTAINS EACH VALUE
// PLACE IN INDIVIDUAL CELLS
Next
End Sub
Hope this helps!
dim arrString() as string
dim strInput as string
dim i as integer
strInput = "Performance;#Recruiting;#Culture and values;#Community Involvement &
Volunteerism;/Talent Development;#Workplace"
arrStrings = strings.split(strInput, ";#")
for i = 1 to ubound(arrstrings)
cells(i, 1) = arrstrings(i)
next i