Interpreting VBA code for moving averages - vba

While I roughly understood my coding at the time of writing it awhile back, I have since forgotten how to interpret the first few parts of it (in bold).
Why 'as long'? My understanding is that this is used when the variable is only to take larger integer values. Since the share values contain several decimals, I am not sure why I chose this over 'double'.
Why/when do we dim a variable as a 'range', and why do we use 'set' at all? My limited understanding of the purpose of the set function is to assign values to 'object' variables. Why is the 'range' an 'object'?
I have completely forgot what the line Set stockValue = Range("B5:B" & lastStockprice) is doing, especially the ampersand.
I've no idea what is going on here:
ReDim stockPrice(stockValue.Count - 1)
For Each cell In stockValue
stockPrice(cell.Row - 5) = cell.Value
Next
Sub MovingAverage()
Dim CumulSum() As Double
Dim MovingAv() As Double
RowCountA = Range("StockPrice").Rows.Count
RowCountB = Range("MovingAv").Rows.Count
ReDim CumulSum(RowCountB)
Dim stockPrice As Variant
Dim lastStockprice **As Long**
lastStockprice = Cells(Rows.Count, "B").End(xlUp).Row
Dim stockValue **As Range**
**Set stockValue = Range("B5:B" & lastStockprice)**
**ReDim stockPrice(stockValue.Count - 1)
For Each cell In stockValue
stockPrice(cell.Row - 5) = cell.Value
Next**
For i = 0 To RowCountB - 1
For k = 0 To 9
CumulSum(i) = CumulSum(i) + stockPrice(i + k)
Next k
Next i
For i = 1 To RowCountB
Range("MovingAv").Cells(i) = CumulSum(i - 1) / 10
Next i
End Sub
If someone could please explain the bolded code for me (I've a very basic knowledge of VBA that extends about as far as matrix multiplication, basic functions and double arrays), it would be greatly appreciated. :)

Dim lastStockprice **As Long**
lastStockprice = Cells(Rows.Count, "B").End(xlUp).Row
This has to be long because we are trying to find the last row in Col B. This is to make the code compatible with xl2007+ (Where there are 1048576 rows). You can see this link on how to get the last row.
Why is the 'range' an 'object'?
See this link. Also see this.
I have completely forgot what the line Set stockValue = Range("B5:B" & lastStockprice) is doing, especially the ampersand.
As mentioned earlier lastStockprice is the last row and & is used to concatenate so that we can set our range. Let's say the last row is 20 then the above code can be written as
Set stockValue = Range("B5:B" & 20)
'OR
Set stockValue = Range("B5:B20")
I've no idea what is going on here: ReDim stockPrice(stockValue.Count - 1)
What the code is trying to do is dynamically increase the size of the array so that it can store more values to it. REDIM (Re-Dimension) I would recommend seeing this link
FOLLOWUP (From comments)
I understand all of it now except this part: For Each cell In stockValue stockPrice(cell.Row - 5) = cell.Value Next**
What that piece of code is doing is looping through every cell in the range stockvalue and then storing the cell value in the array stockPrice
Ex: Let's say we have a range, A1:B2
When we say For each cell in Range("A1:B2"), we are telling the code to loop through every cell in that range (A1, A2, B1, B2)

Related

Subscript out of range for array in VBA [duplicate]

I have declared an array as such Dim rArray() As Variantbut when i try and use the values that is stored in it (as shown below) I get a subscript out of range error. The UBound(rArray)and LBound(rArray) both returns values 14 and 1, but the error occurs at the Debug.Print line.
If I use the for statement as below
For Each rArr in rArray
then it works without issues, but for the purposes I am creating this array I need the flexibility to select each item stored in that order- meaning I need to refer to them using subscripts.
I have tried multiple ways to try and solve this with no luck and spend almost half my day on this one issue. Could anyone point out what I need to change to get this to work.
Set rng = Range("D4", Range("D4").End(xlDown))
rng.NumberFormat = "0"
rArray = rng.Value
For x = UBound(rArray) To LBound(rArray) Step -1
Debug.Print rArray(x)
Next x
Edit: another fact worth mentioning is that he array is declared and used within a Function but it is not passed from or to the function. Can't arrays be declared and used in Functions?
When you assign worksheet values to a variant array, you always end up with a 2-D array that is 1 based (e.g. 1 to something, 1 to something; never 0 to something, 0 to something). If you are getting values from a single column the second Rank is merely 1 to 1.
This can be proven with the following.
Dim x As Long, rArray As Variant, rng As Range
Set rng = Range("D4", Range("D4").End(xlDown))
rng.NumberFormat = "0" 'don't really understand why this is here
rArray = rng.Value
Debug.Print LBound(rArray, 1) & ":" & UBound(rArray, 1)
Debug.Print LBound(rArray, 2) & ":" & UBound(rArray, 2)
For x = UBound(rArray, 1) To LBound(rArray, 1) Step -1
Debug.Print rArray(x, 1)
Next x
So you need to ask for the element in the first rank of the array; it is insufficient to just ask for the element.

VBA MIN and MAX function always returning 0

Hello I am trying to get the MIN and MAX values from the array and it always returns "0" despite anything. My code:
Dim MachineCapacitySmallestArray() As Variant
MachineCapacitySmallestArray = thisworkbook.worksheets(1).range("C25:D25")
SmallestCapacity = Application.Min(MachineCapacitySmallestArray)
in range I have natural numbers
I tried formatting those cells to numbers etc. but nothing works. What is the mistake I'm making and how to fix it?
According to the comments, it seems that your problem is your data, you have likely strings in your cell, not numbers (maybe somehow imported?)
As already mentioned, changing the cell format doesn't change the content of a cell, it just defines how to display data. The number 3.14 can be displayed as 3, as 3.140000, as 00003.14 or as 3.14E+00, nothing changes it's value. However, a String '3.14 is a combination of the characters 3, ., 1 and 4 and has nothing to do with a number. Setting a cell format after the value is in the cell will not convert it to a number.
If you read your data into VBA, VBA will get the exact values from Excel and in your case, you will have to convert it into numbers manually, for example with the following routine. The On Error Resume Next will prevent a type mismatch if a cell doesn't contain something that can be converted into a number.
Sub ArrToNumber(ByRef arr)
Dim i As Long, j As Long
For i = LBound(arr, 1) To UBound(arr, 1)
For j = LBound(arr, 2) To UBound(arr, 2)
On Error Resume Next
arr(i, j) = CDbl(arr(i, j))
On Error GoTo 0
Next
Next
End Sub
Now just add a call to this routine to your code. If you want to have the numbers also in Excel, remove the comment sign from the last statement.
Dim MachineCapacitySmallestArray() As Variant
MachineCapacitySmallestArray = thisworkbook.worksheets(1).range("C25:D25")
ArrToNumber MachineCapacitySmallestArray
SmallestCapacity = Application.Min(MachineCapacitySmallestArray)
' thisworkbook.worksheets(1).range("C25:D25") = MachineCapacitySmallestArray

vb.net read arraylist to excel column of cells

I'm trying to read values from one excel file to arraylists, then use this information to fill another arraylist. what I tried doing was this
For cellcount As Integer = 1 To buildList.Count
oSheet.Range(1, cellcount).Value = buildList(cellcount-1)
oSheet.Range(2, cellcount).Value = streamList(cellcount-1)
Next
and I'm getting an error "Exception from HRESULT: 0x800A03EC"
I can fill just a single cell by doing this
oSheet.Range("A7").Value = buildList(2)
oSheet.Range("B7").Value = streamList(2)
does anybody know a way to increment "A7" to A8, A9, A10, etc. same with B? or of a way to do this as if it were a 2D array? Thanks!
To fill a range, you need a two-dimensional object, even if the range is 1-dimensional.
The range should also be between two cells.
Here is an example assuming we have an array ArrayToAdd, and a cellcount (as you had).
Dim exObArray(ArrayToAdd.length- 1, 0) As Double
'go through the list and add values to objects (2d array)
For a As Integer = 0 To ArrayToAdd.length- 1 Step 1
exObArray(a, 0) = ArrayToAdd(a)
Next
oSheet.Range(oSheet.Cells(1, 0), oSheet.Cells(1, cellcount)).value = exObArray
I'm not sure that I have the range right, but you get the idea. This one goes from (1,0) to (1,cellcount)
got it working by concatenating the number as a variable after the letter and incrementing it each time, as below
For cellcount As Integer = 1 To buildList.Count
oSheet.Range("A" & cellcount + 9).Value = buildList(cellcount - 1)
oSheet.Range("B" & cellcount + 9).Value = streamList(cellcount - 1)
Next
working as I wanted now.

Create new worksheet based on text in coloured cells, and copy data into new worksheet

I have a large data set which I need to manipulate and create individual worksheets. Within column B all cells which are coloured Green I would like to make a new worksheet for. Please see screen shot.
For example I would like to create worksheets titled "Shopping" & "Retail". Once the worksheet is created, I would then like to copy all the data between the "worksheet title" (Green Cells) from columns ("B:C") & ("AI:BH") Please see screen shot below for expected output;
The code I have so far is below as you can see it is not complete as I do not know how I would go about extracting data between the "Green Cells".
Sub wrksheetadd()
Dim r As Range
Dim i As Long
Dim LR As Long
Worksheets("RING Phased").Select
LR = Range("B65536").End(xlUp).Row
Set r = Range("B12:B" & (LR))
For i = r.Rows.Count To 1 Step -1
With r.Cells(i, 1)
If .DisplayFormat.Interior.ColorIndex = 35 Then
MsgBox i
Worksheets.Add(After:=Worksheets(Worksheets.Count)).Name = Cells (i,1).Value
Worksheets("RING Phased").Select
End If
End With
Next i
End Sub
Any help around this would be much appreciated.
Sorry for taking a while to get back to this, I've been somewhat busy the last few days, so I haven't had much time to be on StackOverflow.
Anyway, the way I'd go about this would be to store all the found values in an array, and then loop through that array in order to find the distance between them.
The following code works for me, using some very simplified data, but I think the principle is sound:
Option Explicit
Option Base 0
Sub wrksheetadd()
Dim r As Range, c As Range
Dim i As Long: i = 0
Dim cells_with_color() As Range: ReDim cells_with_color(1)
With Worksheets("RING Phased")
' Since it doesn't seem like the first cell you want to copy from is colored, hardcode that location here.
' This also saves us from having to test if the array is empty later.
Set cells_with_color(i) = .Range("B12")
i = i + 1
Set r = Range(.Range("B13"), .Range("B" & .Cells.Rows.Count).End(xlUp))
' Put all the cells with color in the defined range into the array
For Each c In r
If c.DisplayFormat.Interior.ColorIndex = 35 Then
If i > UBound(cells_with_color) Then
ReDim Preserve cells_with_color(UBound(cells_with_color) + 1)
End If
Set cells_with_color(i) = c
i = i + 1
End If
Next
' Loop through the array, and copy from the previous range value to the current one into a new worksheet
' Reset counter first, we start at 1, since the first range-value (0 in the array) is just the start of where we started checking from
' (Hmm, reusing variables may be bad practice >_>)
i = 1
While i <= UBound(cells_with_color)
Worksheets.Add(After:=Worksheets(Worksheets.Count)).Name = cells_with_color(i).Value
' Set the range to copy - we could just do this in the copy-statement, but hopefully this makes it slightly easier to read
Set r = .Rows(CStr(cells_with_color(i - 1).Row) + 1 & ":" & CStr(cells_with_color(i).Row))
' Change the destination to whereever you want it on the new sheet. I think it has to be in column one, though, since we copy entire rows.
' If you want to refine it a bit, just change whatever you set r to in the previous statement.
r.Copy Destination:=Worksheets(CStr(cells_with_color(i).Value)).Range("A1")
i = i + 1
Wend
End With
End Sub
It probably lacks some error-checking which ought to be in there, but I'll leave that as an exercise to you to figure out. I believe it is functional. Good luck!

Range object returns empty values

I have a set range to a variable in this fashion:
Dim srcRng As Range
Set srcRng = Range(hrwb.Worksheets(1).Range(yomColAddress)(1).Address, _
Cells(hrwb.Worksheets(1).Range(yomColAddress).row + 200, rightMostCol)(1).Address)
for some weird reason when I call
srcRng(1) 'actually instead of 1 is i that runs 1 to srcRng.Count
it doesn't return the upper leftmost cell value. Any ideas why?
(for those who are not familiar with this technique: http://www.cpearson.com/excel/cells.htm)
Informations:
at execution time the variables yomColAddress=$AL$9 and righMostCol=40
hrwb.Worksheets(1).Range(yomColAddress)(1) works as expected.
With MsgBox srcRng(1).Address & " value:" & srcRng(1).Value I get "$AL$9 value:"
The value of AL9 is the text "yom"
The actual code is:
Dim srcRng As Range
Set srcRng = Range(hrwb.Worksheets(1).Range(yomColAddress)(1).Address, Cells(hrwb.Worksheets(1).Range(yomColAddress).row + 200, rightMostCol)(1).Address)
Dim i As Integer
i = 1
While (weekDayCol = 0 And i <= srcRng.count)
If loneHebDayLetter("à", "ä", srcRng(i)) Then'loneHebDayLetter checks some conditions on a cell
weekDayCol = srcRng(i).Column
End If
i = i + 1
Wend
I think I get what goes wrong here:
The code itself is working well but not on the good data (This is a supposition but I just did some tests with a custom workbook)
Short version
Just add srcRng.Select after Set srcRng (no real interest but to understand what it does) and I think you will get what happens if my supposition is correct.
Longer version
When you do Set srcRng = ... it does create the correct Range but it is not linked to any sheet actually ... It just means remember a Range which goes from cell X to cell Y.
The point is: The sheet (let's say "sheet2") where your code is executed isn't the same as the one where the datas are (say "sheet1") so srcRng(1) is understood as Sheets("sheet2").srcRng(1) instead of Sheets("sheet1").srcRng(1) (<- that's what you want)
Even if not elegant, this should work:
Dim srcRng As Range
With hrwb.Worksheets(1)
Set srcRng = Range(.Range(yomColAddress)(1).Address, Cells(.Range(yomColAddress).row + 200, rightMostCol)(1).Address)
Dim i As Integer
i = 1
While (weekDayCol = 0 And i <= srcRng.count)
If loneHebDayLetter("à", "ä", .Range(srcRng.Address)(i).Value) Then 'I assume it take the value not the cell: if it take the cell you may get an error!
weekDayCol = srcRng(i).Column
End If
i = i + 1
Wend
End With
What is important is the use of .Range(srcRng.Address)(i).Value to access the value in the right worksheet! (That's why this trick is not needed here: srcRng(i).Column because colum numbers do not change from one sheet to an other)
(NOTE: I used with to optimize/clarify the code)
If something isn't clear tell me