I got a few arrays and I want to do the following math operation:
For i As Integer = 10 To 100
TransmissionArray(i) = (maxFirstArray(i) - mintranArray(i)) / (maxSecondArray(i) - mintranArray(i))
i = i + 1
Next
The problem is that sometimes mintranArray(i) has higher values than maxFirstArray(i) and maxSecondArray(i). So the program crashes.
With Try Catch the program is not shutting down but I only get TransmissionArray() = Nothing.
Sounds like your TransmissionArray isn't being initialized properly. If you just Dim it like this:
Dim TransmissionArray() As Double
Then it will be Nothing. If you try to assign a value to it in this way, you will get an exception. Normally you can insert a number in the parenthesis (Dim TransmissionArray(10) As Double) and you would have an array of length 10 that you could immediately start assigning values to. But, if you don't know the length before hand, I can think of two options that would work:
Dim TransmissionArray() As Double
For i As Integer = 10 To 100
ReDim Preserve TransmissionArray(i) 'This will increase the size of the array to the value of i, the Preserve keyword also saves the data already stored in the array
TransmissionArray(i) = (maxFirstArray(i) - mintranArray(i)) / (maxSecondArray(i) - mintranArray(i))
'i = i + 1 'Commented this out...i is already incremented once each loop
Next
Or, switch to using a List(Of Double):
Dim TransmissionArray As New List(Of Double)
For i As Integer = 10 To 100
TransmissionArray.Add((maxFirstArray(i) - mintranArray(i)) / (maxSecondArray(i) - mintranArray(i)))
'i = i + 1 'Commented this out...i is already incremented once each loop
Next
Note that the second method would make TransmissionArray 10 items less than the other arrays, due to the fact you are starting the For loop counter at 10, and just adding items to the list.
Related
The code block computes two values for speeds; Vsf and Vro using their corresponding parameter values: Angle, Super-elevation and Radius for each iteration of the for- loop statement. During each loop, it selects the minimum of both speed values. In some scenario's, Angle, super-elevation but most of all, Radius are all null values, leading to Vsf and Vro values of null and hence Vmin of null. I want to eliminate these scenarios and produce just non-zero values for Vmin hence my question.
For i = 1 To CInt(txtNumSections.Text)
ReDim Preserve Vsf(i)
ReDim Preserve Vro(i)
ReDim Preserve Vmin(i)
Vsf(i) = (((0.91544 - 0.00166 * Angle(i) - 0.000002 * W - 0.054248 * Superelevation(i) - Sidefrictionfactor) / 0.013939) * Radius(i)) ^ 0.5
Vro(i) = (((1.05653 - 0.004861 * Angle(i) - 0.000004 * W - 0.314653 * Superelevation(i) - rolloverthreshold) / 0.012729) * Radius(i)) ^ 0.5
Vmin(i) = Math.Min(Vsf(i), Vro(i))
If Vmin(i) <= "0" Then
Vmin(i) = "0"
End If
Next
Dim myList = New List(Of Double)
For Each s In Vmin
If Not String.IsNullOrWhiteSpace(s) Then
myList.Add(s)
End If
Next
Vmin = myList.ToArray()
Since arrays are immutable(you can't add or remove items) you can just re-create it:
myArray = myArray.Where(Function(s) Not String.IsNullOrEmpty(s)).ToArray()
This is a String() but this LINQ query works similar with any other type of array.
A non-LINQ appproach would be to fill a List(of T) and then use ToArray:
Dim myList = New List(Of String)
For Each s In myArray
If Not String.IsNullOrEmpty(s)
myList.Add(s)
End If
Next
myArray = myList.ToArray()
You see that LINQ can make your code more readable and understandable.
Alright guys, I found a workaround this, based on the purpose of the code piece. I simply set all null or negative values to the maximum allowable values. There's some context to it which makes it a sensible approach but I would need to explain the entire operation of the code block which I'm not sure you would have any interest in. Anyway, thanks for your contributions. They are very much appreciated
(Fair Warning, I am self taught on VBA so I apologize in advance for any cringe-worthy coding or notations.)
I have an estimating worksheet in excel. The worksheet will have a section for the user to input variables (which will be an array). The first input variable will "reset" the remaining input variables to a standard value when the first variable is changed. The standard values for the input variables are stored in a function in a module. I am attempting to fill the input variable array with the standard values from the function and then display those values on the sheet. I was easily able to do this without arrays but have had no luck in moving everything into arrays.
This is for excel 2010. I previously did not use arrays and created a new variable when needed, however the estimating sheet has grown much larger and it would be better to use arrays at this point. I have googled this question quite a bit, played around with removing and adding parenthesis, changing the type to Variant, trying to set the input variable array to be a variable that is an array (if that makes sense?), and briefly looked into ParamArray but that does not seem applicable here.
Dim BearingDim(1 To 9, 1 To 4, 1 To 8) As Range
Dim arrBearingGeneral(1 To 5, 1 To 8) As Range
Dim Test As Variant
Private Sub Worksheet_Change(ByVal Target As Range)
'Set General Variable array to cells on the worksheet
For i = 1 To 5
For j = 1 To 8
Set arrBearingGeneral(i, j) = Cells(9 + i, 3 + j)
Next j
Next i
'Set Bearing Input Variables to Cells on the Worksheet
For p = 1 To 4
For i = 1 To 9
Select Case p
Case Is = 1
Set BearingDim(i, p, 1) = Cells(16 + i, 4)
Case Is = 2
Set BearingDim(i, p, 1) = Cells(27 + i, 4)
Case Is = 3
Set BearingDim(i, p, 1) = Cells(37 + i, 4)
Case Is = 4
Set BearingDim(i, p, 1) = Cells(49 + i, 4)
End Select
Next i
Next p
'Autopopulate standard input variables based on Bearing Type
inputMD_StdRocker BearingType:=arrBearingGeneral(1, 1), _
arrBearingDim:=BearingDim
End Sub
Sub inputMD_StdRocker(ByVal BearingType As String, ByRef _
arrBearingDim() As Variant)
Dim arrBearingDim(1 To 9, 1 To 4)
Select Case BearingType
Case Is = "MF50-I"
For j = 1 To 2
arrBearingDim(2, j) = 20
arrBearingDim(3, j) = 9
arrBearingDim(4, j) = 1.75
Next j
arrBearingDim(5, 1) = 15
'There are numerous more select case, but those were removed to keep it
'short
End Select
End Sub
The expected output is my "BearingDim" Array will have certain array index values set to a standard value from the "inputMD_StdRocker" function. Then those values will be displayed in the cell that corresponds to the array index.
Currently, I get a compile error "Type Mismatch, Array or User-Defined Type Expected". I have been able to get around the type mismatch by removing the () from "arrBearingDim()" in the function title for "inputMD_StdRocker" however, it will not pass the values back to my "BearingDim" array.
Any help would be greatly appreciated.
This is a partial answer to what (I think) is a misunderstanding you have of how to use arrays. There are a few problems in your code.
First, you're defining a two-dimensional and a three-dimensional array of Ranges when I believe you really only want to store the values captured from the worksheet. (If I'm wrong, then you are never initializing the array of Ranges, so none of the ranges in the array actually point to anything.)
Secondly, it looks as if your initial array arrBearingGeneral is always filled from the same (static) area of the worksheet. If this is so (and you really do want the values from the cells, not an array of Range objects), then you can create a memory-based array (read this website, especially section 19). So the first part of your code can be reduced to
'--- create and populate a memory-based array
Dim bearingDataArea As Range
Dim arrBearingGeneral(1 To 5, 1 To 8) As Variant
Set bearingDataArea = ThisWorkbook.Sheets("Sheet1").Range("D10:K14")
arrBearingGeneral = bearingDataArea.Value
Optionally of course you can calculate the range of your data instead of hard-coding it ("D10:K14"), but this example follows your own example.
While this isn't a complete answer, hopefully it clears up an issue to get you farther down the road.
This is a tricky one for me to explain, so I'll start with the code I have so far, and later with what I am trying to achieve.
Current Code
Option Explicit
Public eSigTickerArr As Variant
' Public type to save array
Type Watchlist
eSigTicker As String
Op As Double
Hi As Double
Lo As Double
Cl As Double
Vol As Double
BarTime As Variant
End Type
Public WatchlistArr() As Watchlist ' save an array of special type "Watchlist"
'====================================================================
Sub Mainr()
ReDim WatchlistArr(0) ' init array size
eSigTickerArr = Array("Part1", "Part2", "Part3")
For Each eSigTickerElem In eSigTickerArr
' check if first member of array is occupied
If WatchlistArr(0).eSigTicker <> "" Then ' not first time running this code >> increase array size by 1
ReDim Preserve WatchlistArr(UBound(WatchlistArr) + 1) ' increase array size by 1
End If
' ... Some Code, working fine ....
' populate array Type with data (also works)
With WatchlistArr(UBound(WatchlistArr))
.eSigTicker = eSigTickerElem
.Op = LastCSVLine(2)
.Hi = LastCSVLine(3)
.Lo = LastCSVLine(4)
.Cl = LastCSVLine(5)
.Vol = LastCSVLine(6)
.BarTime = LastCSVLine(1)
End With
Next eSigTickerElem
' ******* calculate the average of only "Hi" ******
Dim myAvg
myAvg = WorksheetFunction.Average(WatchlistArr.Hi) '<--- Getting an Error !
End Sub
I'm getting an error at the line above.
My Challenge: I want to get the average only of a certain variable of my type array WatchlistArr, and I don't want to use a loop, as there can be 10,000 records (or more).
Is there any way to get the value with the Average function ?
Should I switch to 2-D array ? or Maybe 3-D array ?
myAvg = WorksheetFunction.Average(WatchlistArr.Hi) '<--- Getting an Error !
Yep. What this code means to do is similar to this:
myAvg = watchListArr.Select(item => item.Hi).Average();
Where item => item.Hi is a selector function that is invoked for every item in watchListArr. The only problem is that this is LINQ / C#, not VBA. VBA doesn't support delegates and other funky stuff even C# couldn't dream to do in v1.0.
But VBA has control flow structures that let you perform an action for every item in an array: use a For loop!
Dim i As Long, total As Double, count As Long
For i = LBound(watchListArr) To UBound(watchListArr)
total = total + watchListArr(i).Hi
If watchListArr(i).Hi <> 0 Then count = count + 1 'assuming zeroes are excluded
Next i
If count <> 0 Then myAvg = total / count
If you want to use Application.WorksheetFunction.Average, you'll need to copy the Hi member of every item in your array into its own array, and give it that array - and that will require... a loop... which is wasted cycles if that loop isn't also computing the average as it goes.
As long as you're not using a For Each loop to iterate the array, you'll do fine. Iterating a 30K items array with a For loop is pretty much instant, no worries there.
You could define WatchlistArr as a 2-D array and then try this logic:
Dim myArray As Variant
myArray = Application.WorksheetFunction.Index(WatchlistArr, 0, 2)
This will return column 2 as as array, which can be passed into the Average method:
myAvg = WorksheetFunction.Average(myArray)
Based on How can I declare a two dimensional string array? I've made my own array but am struggling to retrieve the values.
I get a syntax error which appears to relate to the second (0) line (0) = (((1) / total) * (100 - (vPercentChanger))) but the error might occur on the line above this (see code below).
Error: Syntax error.
Code:
'Test values
Dim highPer As Double = 5
Dim high As Double = 10
Dim medPer As Double = 15
Dim medium As Double = 20
Dim lowPer As Double = 1
Dim low As Double = 2
Dim naPer As Double = 3
Dim na As Double = 4
Dim array1 As Double(,) = New Double(3, 1) {{highPer, high}, {medPer, medium}, {lowPer, low}, {naPer, na}}
Dim tmpList As New List(Of Double)
For i As Integer = 0 To array1.Rank - 1
If (0) > 5 + vPercentChanger Then
(0) = (((1) / total) * (100 - (vPercentChanger)))
End If
Next
Further notes:
I've tried array1(0) and tmpList(0) but both create errors. I believe I am close. I've tried the C# to VB converter but this does not resolve this issue.
As written, there are a few problems with the code.
We have declared array1 as an array with 3 rows with 1 entry in each but the given data is 4 rows with 2 entries in each.
I afraid that I couldn't understand the Values as strings... note. Unless the highPer, high et al. are variable names, they need quotations marks around them. If they are variable names, the variables should have been included in the example to meet the Minimal, Complete, Verifiable example standards.
You have tried both array1(0) and tmpList(0) - what are you trying to achieve?
array1 is a 2D array so we need to address it with 2 indices, e.g. array1(0,0).
Both tmpList and array1 contain strings, comparing the values with numbers or assigning numbers into them seems wrong (does VB perform some sort of implicit conversion? Are you sure that you want to work with strings, perhaps they should be arrays/lists of numbers?
Update:
From the comments, it looks like we have an array representing a list of pairs
{valPct, val}
and we want to iterate through them and check
if valPct > (5 + vtPercentChanger) then
valPct = (val / total) * (100 - vPercentChanger)
We can do this with
dim values as double(,) = {{v1Pct, v1}, {v2Pct, v2}, {v3Pct, v3}}
for index as integer = 0 to values.GetUpperBound(1) -1
if (values(index,0) > (5 + vtPercentChanger)) then
values(index,0) = (values(index,1) / total) * (100 - vPercentChanger)
next
This is unfortunately done with no code checking - using phone on bus - but should give the general shape.
I'm quite new at using arrays and functions in Visual Basic and I cannot seem to figure this out. My problem is that whenever I call the function Fibo it returns 0 no matter the value of n I give it. I'm sure the error is pretty basic.
Any pointer would be really appreciated!
Public Function fibo(n As Integer) As Integer
Dim arrayFib(n + 1) As Integer 'declare array to hold fibonacci
arrayFib(0) = 0 'idem
arrayFib(1) = 1 'declare start value
Dim i As Integer = 2 'start position
While i <= n
arrayFib(i) = arrayFib(i - 1) + arrayFib(i - 2)
i = 1 + i
Return arrayFib(i)
Dim arrayFib(n + 1) As Integer 'declare array to hold fibonacci
We can sort of guess where that +1 came from. You added it because your original code crashed with an IndexOutOfRangeException. Caused by you returning arrayFib(i), i was incremented to be larger than n, its value is n+1 after the loop. And thus returns the value of an element that was never assigned. You didn't fix it correctly :)
Fix the array declaration back the way it was and return arrayFib(n) instead.