Looping thru 2D array using VBA - excel

I have several designs, and each design has several variables.
Using VBA code, I want to loop thru each design, and assign variables to each of the indices of the one design.
I'm having a hard time getting the array dim statement correct, and correctly calling the nth variable of each design.
I've shown VBA code here that uses a message box to display if I am getting the right value from each j loop, and each design.
Any help?
Dim Design(0 To 9) As Variant
Sub main
Design(1) = Array(4,6,2,1)
Design(2) = Array(8,2,6,9)
For i = 1 To 2
For j = 1 to 4
MsgBox (Design(i)(j-1))
Next j
Next i
End sub

Wow, my apologies. I've been trying for WEEKS to get this to work, and in formatting it for this question, it FINALLY worked! Code is good as is.

Related

Trying to store user values into an array

I am trying to create an array of a user set length that users can add values to that will be saved and output on multiple sheets. I am very new to VBA so I do not know if what I am trying to do is possible but I have tried a few methods unsuccessfully.
This is the code I have so far
Sub addCost()
Dim costArray() As Variant
ReDim Preserve costArray(1 To Range("b2").Value)
For i = 1 To Range("b2").Value
costArray(i) = 0
Next i
Dim newCost As Variant
Dim costYear As Variant
newCost = InputBox("New cost amount:")
costYear = InputBox("Year new cost is active:")
costArray(costYear) = newCost
End Sub
Here is what the input tab looks like in excel
With the length of the array being the project lifespan and the add new cost activating the code, clear costs are still in progress. Is there a way for the array to store after multiple executions of the addCost sub?
Thanks!
This link Microsoft shows some methods of store values after the macro ending (in your case, sub addCost)
I think the first solution will be good for you.
Other solutions is use Access to store data (specially if you need these data over time) or a new and clean worksheet where you can store array entries in a cell (This is a very practical solution if the number of entries does not get too big)

Error 1004 when referencing specific cells within a defined range

Edited to add solution: I was trying to do Sumproduct and I'm a big dummy haha
I'm trying to do a pretty simple calculation in VBA where I need to loop through two ranges and multiply specific cells then add the value to a placeholder value.
The code is:
Dim Input_Cas As Range
Set Input_Cas = Worksheets("Calculations").Range("A2:A51")
Dim Input_Conc As Range
Set Input_Conc = Worksheets("Calculations").Range("C2:C51")
i = 1
Do Until IsEmpty(Range("Input_Cas")(i)) = True
Tkm = Tkm + Range("Input_Tki")(i) * (Range("Input_Conc")(i) / 100)
i = i + 1
Loop
Mix_Tkm = Tkm
The Ranges defined as Input_Conc, Input_Tki, Input_Cas are all in the active sheet and Dim/Set in code above this block.
Tkm is double and Mix_Tkm is a Dim/Set range as well.
The Error 1004 kicks out in the first line of the Do Until ... Loop.
Since the syntax doesn't seem to be causing any issues in the IsEmpty(Range("Input_Cas")(i)) = True I'm not sure why that same syntax doesn't work below it. All cells referenced contain numerical values as well, just in case that is relevant.
I love you wonderful people and thanks for your help in advance.
Edit: The Dim/Set for the ranges are
Dim Input_Cas As Range
Set Input_Cas = Worksheets("Calculations").Range("A2:A51")
Dim Input_Conc As Range
Set Input_Conc = Worksheets("Calculations").Range("C2:C51")
Dim Input_Tki As Range
Set Input_Tki = Worksheets("Calculations").Range("G2:G51")
As suggested I am posting the answer to self for folks from the future.
I was attempting to recreate the Sumproduct function from excel within VBA by making a loop. What I was attempting was more effectively done in excel. I didn't know Sumproduct was a thing and it does exactly what I was attempting.
Thanks to Bigben for providing the solution I couldn't find for myself.

Excel VBA performance of worksheetfunction vs code, for arrays

In a quest to speed up my VBA code I searched for methods online. A lot of methods pass by, and one of them that keeps returning seems to be to use worksheetfunctions in stead of code, where possible.
My experience however is contrary to that tip. I find that worksheetfunctions tend to be slower than my code. My simple test below shows that the code is about twice faster than the worksheetfunction. I found the same results with other functions, like MATCH.
My question is then, do you VBA'ers tend to use code or worksheetfunctions? Are there reasons to use the functions over code (besides the couple of lines of extra code)?
Sub testSum()
Dim testarray(0 To 10000) As Variant
Dim val As Variant
Dim valSum As Variant
Dim i As Long, j As Long
Dim t As Single
' create testarray
For i = 0 To 10000
testarray(i) = Rnd
Next
For i = 0 To 10000 Step 100
testarray(i) = "text"
Next
' measure code
t = Timer
For j = 1 To 10000
valSum = 0
For Each val In testarray
If IsNumeric(val) Then valSum = valSum + val
Next
Next
Debug.Print "Array: ", Int(valSum), Timer - t
' measure function
t = Timer
For j = 1 To 10000
valSum = 0
valSum = Application.WorksheetFunction.Sum(testarray)
Next
Debug.Print "Sum: ", Int(valSum), Timer - t
End Sub
I prefer to use the worksheet function in the worksheet. Measuring the function in the macro is an unfair test as the VBA environment must switch to the Excel environment to get the results and this adds an overhead that does not exist otherwise.
As a general coding rule, my priorities are:
use Native Excel formulas, including setting up helper cells or
columns.
use VBA with arrays
use VBA with ranges
As a test:
set up 10,000 rows with random numbers
set up your formula in one cell (B1) =Sum(A1:A10000)
select B1 and calculate the cell
Set up a macro - the below is a quick and dirty based on your code above - it could be neater by using properly qualified ranges and Option Explicit.
Sub TestNativeSpeed()
Dim j As Long
Dim t As Single
t = Timer
For j = 1 To 10000
Range("B1").Dirty
Next
Debug.Print "Native Sum: ", Int(Range("B1").Value), Timer - t
End Sub
I set up my cells with the formula =Rand() and I got the results (single run only):
Native Sum: 4990 16.53125
I reset them to values only (consistent with your code) and I got the results (single run only):
Native Sum: 4990 1.765625
I ran your code and got (single run only):
Array: 4917 4.386719
Sum: 4917 27.73438
What the above shows is that Native Excel is usually the fastest and most efficient approach. But arrays (where it doesn't have to keep switching between the VBA and Excel models) are the next in line in terms of efficiency.
I almost exclusively use code.
It's probably an issue, but I hate using functions because I find that I always have to go back and edit bits and it just gets confusing, where I can just mess around with one Sub if I'm using code.
To answer your code, I would likely say just use arrays to sum - that'll shed a few picoSeconds
Try and use Code Review to get those brainiacs to improve on your speeds

Textbox_change() event only on keyboard input

Function FtoC(ByVal Temp As Variant) As Variant
FtoC = Round((Temp - 32) * 5 / 9, 1)
End Function
Function CtoF(ByVal Temp As Variant) As Variant
CtoF = Round(Temp * 9 / 5 + 32, 1)
End Function
Private Sub Temp_F_Change()
If Temp_F <> "" Then Temp_C = FtoC(Temp_F)
End Sub
Private Sub Temp_C_Change()
If Temp_C <> "" Then Temp_F = CtoF(Temp_C)
End Sub
I have the above functions/subs for a little project to learn/sharpen my VBA skills. The logic is all fine and dandy. However, ideally I would only like the textbox_change event to only run if the change was due to a keyboard input (or a not sub output). A working example would be starting from blanks for each if I input 78 to Temp_F then it converts to 25.6 outputs it to Temp_C. Temp_C has now changed and it then converts 25.6 to 78.1 and outputs it to Temp_F, then of course temp_f has changed and it converts it to 25.6 which is not a change bringing both subs to their end points. Ideally i would like for it to take 78F convert to 25.6C and for the form to recognize that the Temp_C field change was due to a sub output(or not due to a keyboard input) and exit the temp_c_change() sub Is this even possible with VBA, if so how simple/complex is it? I tooled around with the idea of using a counter that is reset by a keypress event but my scripting skills aren't good enough to make it work. I thank you guys in advance and apologize that my question is beneath the talent that I've witnessed searching this site for answers before.
Well, for something this small you could use a worksheet_change event that first checks the target cell to see if either of the two temperature cells changed (assuming they do not move around the sheet - if they do, consider a named range). If either of those cells changed, then create the appropriate conversion formula as a string and put it in the other cell.
My apologies, I just noticed that you are working with a textbox event and not a worksheet event.
What happens to the data after it is converted? Does it go into a cell or get plugged into another function/sub? Right now, your code will just perform a calculation but doesn't show it or do anything else with it. Maybe you need to approach it from whatever that happens next.

Error while copying more than 8202 characters from one cell to another

Problem - I have around more than 8202 characters in once cell say Range("A1").
Now I would like to copy the content of cell(A1) to cell(A2) using VBA. I'm using below Code
Sheets("XYZ").Range("A2") = Sheets("XYZ").Range("A1")
After the execution of the Code. It gives "Application Defined Or Object Defined Error !!"
Please help/assist with your expert comments.
Observation - If I reduce the length of "A1" cell to 8202 or less then about code works!
I'm Confused. Pls assist.
Change your code to
Sheets("XYZ").Range("A2") = Sheets("XYZ").Range("A1").Value
and it will work.
Not really sure why though, as .Value is the default property of a range.
I was able to duplicate your error with the following:
Sub Test8202Copy()
Dim wks As Worksheet
Set wks = Worksheets("Sheet1")
Dim x As String
For i = 0 To 8202
x = x + "a"
Next i
wks.Range("A1").Value = x
wks.Range("A2") = wks.Range("A1")
End Sub
I was able to solve the error by adding .value to the copy.
Sub Test8202Copy()
Dim wks As Worksheet
Set wks = Worksheets("Sheet1")
Dim x As String
For i = 0 To 8202
x = x + "a"
Next i
wks.Range("A1").Value = x
wks.Range("A2").Value = wks.Range("A1").Value
End Sub
Using an intermediate variable without the use of .Value seems to work:
Dim y As Variant
y = wks.Range("A1")
wks.Range("A2") = y
My guess so far is that 8202 exceed the character limit of the data type used when you don't define .Value. The in cell limit length is 32,767 (MS Excel 2010) which is almost 4x the 8201 value that clears.
#Chris Neilsen provided the most practical and elegant solution to the problem (his code snippet follows):
Sheets("XYZ").Range("A2") = Sheets("XYZ").Range("A1").Value
In order to investigate and understand the possible cause of this strange behavior (may be a bug) of the Range object, I've posted couple comments, which are summarized below:
There is a conceptual difference between the original expression (see below):
Sheets("XYZ").Range("A2") = Sheets("XYZ").Range("A1")
and solution proposed by #Chris Neilsen, namely: original expression is implicitly assigning the Range object var (essentially, a pointer) to another Range object, like demonstrated in the following code snippet with explicit assignment:
Set rng = Sheets("XYZ").Range("A1")
Sheets("XYZ").Range("A2") = rng
while proposed solution explicitly passes the value property. Still, the reason why assigning a Range object failed for a value with string.Length>8202 is currently unclear (it may be caused by some internal nuances of the Excel Range object implementation).
Many thanks for posting this interesting question and fruitful discussion.
Regards,
This limit (see below re excel-2007) is covered in this MSDN article although interestingly it implies a vba array is invoved
Separately as per https://stackoverflow.com/a/13665363/641067 excel-2003 cant handle array strings longer than 911 characters, whereas the article below references 1823 character
SYMPTOMS
When you run a Microsoft Visual Basic for Applications (VBA) macro to transfer data from a VBA array that contains strings of data to a range of cells in a Microsoft Excel worksheet, the data may be truncated (cut off).
Note In Microsoft Office Excel 2003 and in later versions of Excel, you may receive the following error message when you run the VBA macro in the Visual Basic Editor:
Run-time error '1004'
CAUSE
This problem may occur when one of the following conditions is true:
In Excel 2007, the VBA array is longer than 8,203 characters in length.
In Excel 2003 and in earlier versions of Excel, the VBA array is longer than 1,823 characters in length

Resources