Expression too complex error - vba

I know this question gets asked quite a bit, but I haven't seen an answer that I can apply to my issue. It seems that this error can be caused by quite a few things.
First of all, here is the code:
SurfArea = 19.63495408
Volume = 12.2718463
DeSimpleFinal = 0.009336098
Counter = 13
pi = 4*atn(1)
tracker = 0
stepamount = (Range("A" & Counter + 1).Value) / 1000
If Range("XFD1048508").Value = 1 Then
For x = 0 To Range("A" & Counter + 1).Value Step Stepamount
tracker = tracker + 1
ActiveSheet.Range("XEY" & tracker).Value = ((2 * SurfArea) / Volume) * Sqr((DeSimpleFinal * x) / pi)
ActiveSheet.Range("XEX" & tracker).Value = x
Next
Else
End If
I've decided to leave (Range("A" & Counter + 1).Value) on, because I think it might be relevant to why the code is breaking down. That cell is A14 and has the value 11 inside of it.
The line that gets flagged when I debug is the first line of the For loop. The loop doesn't even go through one iteration.
Does anybody have an idea of what it could be? I changed all my data types to variant to see if that was the issue, but that did nothing. Thank you for your help!
EDIT: I should note that the value of that range SHOULD be one, so that it does go through the loop.

I don't know anywhere enough about VBA's internals to understand why, but I do know that simplifying the expression that sets the limit on a FOR loop will eliminate the Error 16 - Expression Too Complex problem. (The response to this SO post as well as discussion elsewhere on the web comes to pretty much the same conclusion.)
Just declare a new variable, say, StopAmount, assign to it the expression you used in the FOR condition, and then replace the expression in the FOR with the name of the new variable. You get something like:
StopAmount = Range("A" & Counter + 1).Value
......
For x = 0 To StopAmount Step Stepamount
......
That said, there are certainly some oddities here.
For example, your original FOR condition worked fine if the iterator variable x is declared as a Variant, either implicitly or explicitly. (I declared all the variables for my tests.)
However, if x is dimensioned as a Double, the error returned. This is despite the fact that TypeName(x) showed the Variant x as a Double after the Range(..).Value assignment is made.
For x = 0 To Range("A14").Value Step Stepamount also ran with no problem.
And For x = 0 To Cells(Counter + 1, 1).Value Step Stepamount worked, too.

Related

#ERROR: Unable to get match property of the worksheet class. I have already tried solutions available online

NOTE: My problem was not solved by other similar questions on this as well as other sites. Please have a fair view at my question before judging the same
I am trying to perform a task in which first I have to identify the smallest, 2nd smallest numbers and so on and according to this I have to copy data from one column to another. This will continue until the sum of the copied values becomes grater than or equal to certain value in the sheet (Here row no. for the comparison is given by variable "b"). This will be repeated for 172 different sets which are repeated after every 43 cells.
I have written the following code:
Dim m As Range, k As Double, j As Double, b As Double, lIndex As Double, a As Double
Set m = ActiveSheet.Range("E3:E40")
For i = 1 To 172
j = 1
b = 45 + 43 * (i - 1)
For k = 1 To 38
a = Application.Small(m, j)
lIndex = Application.WorksheetFunction.Match(a, m, 0)
If Cells(b, 7).Value < Cells(b, 1).Value Then
Cells(lIndex, 7).Value = Cells(lIndex, 2).Value
Else
End If
j = j + 1
Next k
Set m = m.Offset(43)
Next i
Now there is an error that pops up saying, Unable to get match property of the worksheet class.
NOTE: I have tried solutions online.
Can there be any other way to do it
OR
Is there something wrong I am doing logically or in the syntax as I am new to excel VBAs and coding itself.
a = Application.Small(m, j) will surely return an Error Code when j is actually bigger that the size of te range m. In your code, the range m = Range("E3:E40") has 38 cells, but j can go as high as 38 * 172.
Then you try to call Match with an error code as the first parameter a. This resuts in run-time error. Note here that Application.Match would result in an error code while WorksheetFunction.Match raises a run-time error.
In all cases, no error should occur in your Match if you had fetched correctly the "kth smallest" element. Without being able to check all of you code, I guess what you wanted here was
a = Application.Small(m, k) ' <--- k, not j
And then no error should occur in *.Match(a, m, 0).
After checking your code:
After getting the smallest value, the next value of j should be a + 1 not j + 1.
Why? because if your smallest value is 4 from (4, 6, 10)
on first loop, j = 1, small will return 4.
on second loop, j = 2, small will still return 4, instead of 6.

vba - Macro producing incorrect results when run, but when stepping into results are correct

I have a macro that inserts a VLOOKUP into a column. The macro has to take a number stored as text and convert it to a number, before looking up that number in another sheet.
The macro always produces the same results, such as reaching row 43 before starting to produce erroneous results however when using F8 to step through the code, these incorrect results are not produced.
The erroneous results are that the value placed into col 13 is not equal to the number stored as text. Mostly it seems as though values from rows above and below, sometimes 2 rows below are being inserted to col 13. Almost seems to me as if 2 different threads are running at 2 different speeds or something?
If anyone could have a look at the loop causing the errors I would be grateful, thanks.
For counter = 2 To NumRowsList
checker = CInt(Sheets("Sheet2").Cells(counter, 3)
Sheets("Sheet2").Cells(counter, 13).Value = checker
'Call WaitFor(0.5)
If checker < 4000 Then
Sheets("Sheet2").Cells(counter, 14) = "=VLOOKUP(M" & counter & ",Sheet4!E2:F126,2,FALSE)"
Else
Sheets("Sheet2").Cells(counter, 14) = "=VLOOKUP(M" & counter & ",Sheet5!B2:C200,2,FALSE)"
End If
Next counter
I have tried a few similar variations of this code, such as using the value stored in col 13 directly rather than using the cell reference in the VLOOKUP, always producing the same results.
I even used the waitfor function to try and create a delay hoping it may synchronise the operations, but it did not help and using a delay of more than 0.5 would cause the run time of the macro to be too big.
UPDATE:
I did not find a perfect solution, only a long hand work around. I simply combined the Vlookups onto a single sheet, and converted the numbers stored as text to numbers outside of the vba routine. This took the error away from the number calculation (just col C * 1), and then the vlookups were looking up the correct values. Thank you for the help, regardless.
you can avoid looping, checker and all those If-Then-Else, like follows
edited to account for VlookUp range depending on VlookUp value
With Worksheets("Sheet2")
.Range("N2", .Cells(NumRowsList, 14)).FormulaR1C1 = "=VLOOKUP(Value(RC3),IF(Value(RC3)<4000,Sheet4!R2C5:R126C6,Sheet4!R2C2:R200C3),2,FALSE)"
End With
The following works for me with my test data, but you'll need to see if it works for you... (also are you turning off calculation or events? I don't know if this might have an issue?)
I find it preferable to set a reference to the sheet you want to use rather than access it directly, and this may help?
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet2")
Dim VLURange As String, checker As Long
For counter = 2 To 200 ' NumRowsList
checker = CLng(ws.Cells(counter, 3).Value)
ws.Cells(counter, 13) = checker
VLURange = IIf(checker < 4000, "Sheet4!E2:F126", "Sheet5!B2:C200")
ws.Cells(counter, 14) = "=VLOOKUP(M" & counter & ", " & VLURange & ", 2, FALSE)"
Next counter

Excel VBA For loop in range contains gaps of 0's in sequence

I have isolated the problem and simplified the code to the root cause. More frustrating is that this loop works elsewhere without this error.
If you see the comments in the sequence here, there are 6 cells in the middle of the loop that turn into 0, and then after this 6 cell gap of 0's the loop works. I did use a msgbox to confirm the values were there. For whatever reason rows 130-135 always read as 0 though.
For x = 1 To 140
Cells(3 + x, "AW").Value = 70
'MsgBox (Cells(3 + x, "AW").Value)
'MsgBox confirms the correct value
'rows 130-135 are always empty with 0
Next
Any help greatly appreciated - very stumped at such a simple thing!
it was a simple logical error that was nested inside:
For a = 1 To Number_of_CalcRows
Cells(137 + a, "AW").Value = TenkanCurrent
Next
The problem was that I has not declared the TenkanCurrent with a value.

The do while loop structure

In the do while loop structure usually there's a part where you declare a variable equal to a number (in this case i) and then in a second part you make a increment (i+1). I've made this example in vba, but the structure could be repeated in several different programming languages like the for in php when you're getting data from a database. Now, what I would like to understand better is the relation between the previous mentioned declarations, that is i = some number and i = i + 1 . Wouldn't this generate a problem of interpretation since you're declaring a variable to something and then assigning a different value right after it? Is the second declaration of the variable value, i = i + 1, a new variable calling the previous one or both i's are the same? This is the general orientation I intend with this question. I think explaining the scoop of both variables would help understanding. Thanks!
Sub DoWhile()
Dim x, i, sum
x = 10
i = 1
sum = 0
Do While i < x
sum = sum + i
i = i + 1
Loop
MsgBox “Sum = ” & sum
End Sub
A variable is really just a location in memory. That location can have any value. By setting i=i+1, you're really saying "take the value at position i, add 1 to it, and store it at position i". No new variable is created. There's no problem with the computer interpreting this- what it cares about is the location of i, which isn't changing. It still knows where to find i, regardless of how many times you change the value there.
Since you have created the variable i as a global variable, any reference or modification to i in the sub will be on the same variable. That being said:
Dim i as int
i = 1
Do while i < 11
MsgBox("The value of i is: " & i)
i = i + 1
Loop
would display 10 messageboxes showing the value of i being between 1 and 10.
When the program encounters i = i + 1, the computer 'sees' this as take the value of i, add one to it, and store the result in the variable i.
Hope that helps.

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