Finding max value of a loop with VBA - vba

I am trying to find max value of a loop. First, I have two random arrays and I want to find these two arrays correlation coefficient. Then, I want to calculate it multiple times as much as "I3" cell. After that, I want to write a code which finds max correlation coefficient from this calculation. I wrote the code below but it didn't work.
Sub Macro1()
Dim i As Long
For i = 1 To Range("I3")
Calculate
Next
DMax = Application.WorksheetFunction.Max("A2")
Range("I4").Value = DMax
End Sub
Any help is appreciated.

Your Max-Function needs a proper argument. Just typing "A2" doesn't work in VBA. Try:
DMax = Application.WorksheetFunction.Max(Range("A2"))
This will give you the max-Value of the Array A2. But keep in mind that the max-Value of a range consisting of a single cell is always the cell value.
If you want to calculate the maximum value of all iterations, you should use the max-function in each iteration (inside for-loop) and store it's value. In each following iteration you should then overwrite the max-Value if your new max value is larger than the old one. Just like this:
Sub Macro1()
Dim i As Long
DMax = 0
For i = 1 To Range("I3")
Calculate
DMax2 = Application.WorksheetFunction.Max(Range(...))
If DMax2 > DMax Then DMax = DMax2
Next i
Range("I4").Value = DMax
This will give you the max-Value of Range(...) of all iterations.

I barely understand your code, but the solution will be nasted loop. Suppose you have two sets of numbers: A2 (Cells(2, 1)) through I2 (Cells(2, 7)) and A3 (Cells(3, 1)) through I3 (Cells(3, 7)). You want to calculate partial correlation and find what was the maximum value of it.
For i = 1 To 7
For j = 1 To i
'Calculate the correlation
Next j
'here you have partial coefficient and you can compare it,
'if it is greater than previous one then save it and store
Next i

For i = 1 To Range("I3").value 'to calculate from 1 to the value in that cell
what i would recommend for your question.
For i = 1 To 10 ' loop 10 times
For j = 1 To i ' here it will allow you to check your stuff multiple times before moving on to the next value
arr1(i) = arr2(j) ' see if your array match
Next j
Next i

Related

Nested loop not reapeating in VBA script

I am trying to iterate through every possible combination of integers in an array. Each array position has its own minimum and maximum possible integers. I have been able to do this with the following code:
'loop through each possible integer in each cell in the array from corresponding minimum to corresponding maximum
For g1 = MinG1 to MaxG1
For g2 = MinG2 To MaxG2
For g3 = MinG3 To MaxG3
For g4 = MinG4 To MaxG4
For g5 = MinG5 To MaxG5
'... and so on until...
For g36 = Min36 To MaxG36
Next
'... and so on until...
Next
Next
Next
Next
Next
Obviously it's slow and ugly, but it works and cycles through every possible iteration of integers within each corresponding constraint. I am trying to simplify it greatly using arrays and doing the following:
'loop through each cell in the array
Dim i As Long
Dim j As Long
For i = UBound(GRange) To LBound(GRange) Step -1
'loop through each possible integer in current cell from corresponding minimum to corresponding maximum
For j = MinGRange(i, 1) To MaxGRange(i, 1)
GRange(i, 1) = j
Next
Next
My problem is that it cycles through each cell from minimum to maximum value, but doesn't repeat when the next cell iterates (ie in my ugly code, G36 will return to its minimum and start iterating again when G35 iterates to the next number). I have not found a solution to show me how to get that to happen.
I don't want a 35 stage nested loop. What is it I am missing?

Converting input range to array in function

I have been learning VBA and thought I was getting the hang of it, but for some reason this basic task is eluding me. I am trying to create a function where I select an input region of numbers (really only one row or column), and then output the summation of the numbers in a cell. Here is my code:
Function CashFlow(CashArray As Excel.Range)
Dim cashflows() As Variant
cashflows = CashArray.Value
amount = CashArray.Rows.Count
dim y()
redim y(amount)
Sum = 0
For i = 1 To amount
y(i) = cashflows(i)
Sum = Sum + y(i)
Next i
CashFlow = Sum
End Function
Despite me knowing how to do essentially this in a subroutine, the fact that I'm getting my data from the function's input is throwing me off. How do I accomplish this task?
Just to summarize the above comments, please give the following code a try:
Option Explicit
Function CashFlow(CashArray As Excel.Range)
Dim sum As Double
Dim x As Long, y As Long
Dim cashflows() As Variant
cashflows = CashArray.Value
sum = 0
For y = LBound(cashflows, 1) To UBound(cashflows, 1)
For x = LBound(cashflows, 2) To UBound(cashflows, 2)
sum = sum + cashflows(y, x)
Next x
Next y
CashFlow = sum
End Function
Note, that this code summarizes all cells in the given range (even if there are multiple rows and columns in that range). Basically, the range is stored in the array cashflows. As mentioned in the comments, this will yield a two-dimensional array. The function LBound(cashflows) will give you the Lower Boundary of that array.
By specifying LBound(cashflows, 1) I am specifically asking for the lower boundary of the first dimension (in this case the rows). UBound returns the Upper Boundary of that array for the specified dimension. Similarily UBound(cashflows, 2) returns the last column (second dimension) of the given array.
Remark: I am always using LBound() and UBound() in my code instead of starting with 0 or 1 to avoid coding errors. Some people prefer Option Base 0 and some prefer Option Base 1. While neither will have an impact on the above (as ranges always yield an array starting with 1) it is just good coding practice to prevent bugs in the future.

How to shrink the data from multiple columns into one column

hopefully someone will be able to help me. I need to write a query, which would shrink the data from multiple columns (in my case from columns A:H) into one column.
The original file looks like this:
I need to shrink the data one by one by rows. I mean, the query has to check the first row and take the data (name), and put it into "a new column" then check the second column and do the same, and continue like this one by one. The table has 170 rows.
I found a query that is shrinking the data from multiple columns into one column but in another order than I need. The query is taking as first all data from a column A and putting it into "a new column", then taking all data from a column B and putting it into "a new column" under the data from the previous column (column A).
This is the query I tried to apply:
Please could somebody help me with it? I have to admit that I have not use UBound and LBound functions and I am getting pretty lost here. :(
I will be thankful for any advise how to adjust this query.
Many thanks in advance! :)
Try this. I'm first setting your range to an array. I then loop through the array and 'slice' each row using Application.Index. It then Joins all the content in that row together before Trimming the whitespace left over from either end. This leaves me with the one value in my results array (tmp). The code then clears your source data before leaving all your data in one column.
Sub CombineColumns()
Dim rng As Range
Dim tmp As Variant, vaCells As Variant
Dim i As Long
Set rng = Sheets("DATA").Range("A2:H200")
vaCells = rng.Value2
ReDim tmp(LBound(vaCells) To UBound(vaCells))
For i = LBound(tmp) To UBound(tmp)
tmp(i) = Trim(Join(Application.Index(vaCells, i, 0)))
Next i
With rng
.ClearContents
.Cells(1).Resize(UBound(tmp)).Value2 = Application.Transpose(tmp)
End With
End Sub
LBound returns the lowest position in the array (usually 0 or 1) and UBound returns the highest
I think something like this
for i = 1 to 170
for y = 1 to 8
if worksheets("trainers").cells(i,y).value <> "" then
worksheets("output").cells(i,1).value = worksheets("trainers").cells(i,y).value
exit for
end if
next y
next i
or on same sheet
For i = 1 To 170
Z = 0
For y = 1 To 8
If Cells(i, y).Value = "" Then
Cells(i, y).Delete Shift:=xlToLeft
Z = Z + 1
If Z <= 8 Then y = y - 1
End If
Next y
Next i

Peak over treshold method - VBA - Excel

I really hope you can help me with the following question.
I have a dataset and I need to filter for some values. This is a dataset for wave analysis, and I need to filter out for the higstest values. The so called peak over treshold method. I want to filter out the storms in de wave dataset.
I can do this with the following: A storm is defined when the waveheight is above a certain value, for example 2.5 meters. The waveheight is measured every 3 hours.
So in the dataset I can do an If(B3>$A$1; B3;0). A1 = 2,5 m. Now I have filtered for waveheights. So now I can see in my dataset rows straight after each other with values higher than 2,5 meters, because a storm last serveral hours. See picture 1 as example:
[Picture 1][1]
So if a certain value is above X, then return that value, otherwise return zero. Now comes the hard part:
Now I need the highest value of that strip for values above 2,5 meters. As this is a big(!) dataset, I have a lot of datapoints. So I have several 'storms', which don't always last as long. So the values that are higher than 2,5 meters aren't always 3 rows, sometimes more. See picture 2picture 2
I need to compute the highst value in Column i, for each storm. Because each storm doens't last as long, I probally need to write code in VBA. Could anybody help me with this? I've been stuck for 6 days, but my VBA code doens't work and I do not have much experience with VBA. If anybody could help me that would be very much appreciated!
Kind regards,
Jeroen
EDIT as a reply on -Excel Developers-
I think I'm almost there, thank u very much for replying!! I am probably misreading the code, but a I have still a slight difficulty in computing the highstest value for each storm I think it should look something like this, as seen in picture 3.Picture 3
The highest value of each storm should be printed in the next column, as seen in picture 3. It probably says it all in the code, but I am misreading it.
Thank u very much for you answer! I really hope you can help me with the last part :-)
Kind regards,
Jeroen
You will have to iterate over all the values in column i. For every storm, find the highest value. A storm starts when a 0 is followed by a positive value, and ends when a positive value is followed by a 0. So something like this:
Sub FindHighestValue()
Dim vData As Variant
Dim Storms As Collection
Dim ndx As Long
Dim ndxStorm As Long
Dim MaxValue As Double
Dim Previous As Double
Dim InStorm As Boolean
vData = Sheet1.Range("I8:I21").Value 'Change this to whatever range your wave heights are in
Set Storms = New Collection
Previous = 0
InStorm = False
For ndx = LBound(vData, 1) To UBound(vData, 1)
If vData(ndx, 1) > 0 And Previous = 0 Then
'A storm has started
MaxValue = vData(ndx, 1)
InStorm = True
End If
If InStorm And vData(ndx, 1) > MaxValue Then
MaxValue = vData(ndx, 1)
End If
If (vData(ndx, 1) = 0 And Previous > 0) Or (ndx = UBound(vData, 1)) Then
'A storm has ended
InStorm = False
Storms.Add MaxValue
End If
Previous = vData(ndx, 1)
Next
If Storms.Count > 0 Then
For ndx = 1 To Storms.Count
Debug.Print ndx & ": " & Storms(ndx)
Next
End If
End Sub

Inside a loop, how to indicate "all rows" when taking the mean of multiple columns (Visual Basic)

I have a loop wherein I take the mean of several columns of numbers with the same number of rows each.
The point of the loop is to capture these means in a new vector.
So for each loop I need to indicate "all rows". In matlab this would be easy, just use ":" But I can't figure out what the analogy is in VB. Please help! Thanks.
(Please advise me as to what I put in the code below where I have ALLROWS).
My attempt so far:
For i = 1 To CA
mrCA11(i) = Application.WorksheetFunction.Average(revCA11(**ALLROWS**,i))
Next i
In matlab this would be:
For i = 1:CA
mrCA11(i) = mean(revCA11(:,i));
Next i
EDIT: I've also tried this trick to no avail:
For j = 1 To CA
For i = 1 To s11
temp11(i) = revCA11(i, j)
Next i
mrCA11(j) = Application.WorksheetFunction.Average(temp11)
Next j
I get the error message: "Unable to get the Average property of the Worksheet Function class"
As everybody (Tim and shahkalpesh at least) pointed out, we need to understand what is revCall or more specifically, we need to understand how you want to give them ALL ROWS in argument.
Finding the last row (or column or cell)
A common Excel issue is to find the last used row / column / cell.
This will give you the end of your vector.
Excel give you several methods to deal with this:
xlTypeLastCell
Last cell used in the entire sheet (regardless if it's used in column A or not)
lastRow = ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row
End(xlUp)
Last cell used (including blanks in-between) in Column A is as simple as this:
lastRow = Range("A" & Rows.Count).End(xlUp).Row
End(xlToLeft)
Last cell used (including blanks in-between) in Row 1 is as simple as this:
lastRow = ActiveSheet.Cells(1, Columns.Count).End(xlToLeft).Row
UsedRange
Last cell used in the WorkSheet (according to Excel interpretation):
Set rangeLastCell = ActiveSheet.UsedRange
Using an array as argument
The methods above told you how to find the last row (if this is what you need). You can then easily create your vector and use it in your procedure revCA11.
You can either give an array as argument as Tim pointed out in his answer with this kind of statement:
myArray = ActiveSheet.Range("A1", Cells(lastRow, lastColumn).Value
Or you can use the integer (or long) to build your vector inside your procedure as simple as declaring a range:
Range("A1:A" & lastRow)
You might clarify exactly how revCA11 is declared/created, but maybe something along these lines might work for you:
Sub Tester()
Dim arr, x
arr = ActiveSheet.Range("A1:D5").Value '2-D array
'average each column
Debug.Print "Columns:"
For x = 1 To UBound(arr, 2)
Debug.Print x, Application.Average(Application.Index(arr, 0, x))
Next x
'average each row
Debug.Print "Rows:"
For x = 1 To UBound(arr, 1)
Debug.Print x, Application.Average(Application.Index(arr, x, 0))
Next x
End Sub