My Original formula is as follows:
=INDEX(MIR!$A:$A,MATCH(1,(MIR!$H:$H=TRI!$W2)*(MIR!$I:$I=TRI!$L2),0))
I created the following VBA Code for this and while the code does add the formula to the appropriate range, the formula does NOT work. It's as if the Array portion is not being applied. I've looked everywhere to figure this out but I obviously am not looking in the right spot. Please advise.
Range("B2").Select
Selection.FormulaArray = _
"=INDEX(MIR!C1,MATCH(1,(MIR!C8=TRI!RC23)*(MIR!C9=TRI!RC12),0))"
Range("B2", "B" & Cells(Rows.Count, 1).End(xlUp).Row).FillDown
End Sub
You are using xlR1C1 notation but VBA is reading it as xlA1 notation. MIR!C1 is not MIR!A:A, it is first row, third column on the MIR worksheet (e.g. MIR!C1). The formula is put on the worksheet as,
=INDEX(MIR!C1,MATCH(1,(MIR!C8=TRI!RC23)*(MIR!C9=TRI!RC12),0))
Use a formula in xlA1 notation.
Range("B2").FormulaArray = "=INDEX(MIR!$A:$A,MATCH(1,(MIR!$H:$H=TRI!$W2)*(MIR!$I:$I=TRI!$L2),0))"
Btw, you should really cut those full column references in the MATCH down to the used data range.
Related
I am trying to run the following procedure that entails placing an array formula in a range ("CA2010") on a sheet ("Slate Data").
I've tested the the array formula many times and it produces the desired results.
The sub below gets
run-time '1004' error: Unable to set the FormulaArray property of the Range class.
Sub countuniqueBINs()
Dim placementoutlook As Workbook
Set placementoutlook = Excel.Workbooks("Placement Outlook")
Dim sdws As Worksheet
Set sdws = placementoutlook.Sheets("Slate Data")
sdws.Range("CA2010").NumberFormat = "general"
sdws.Range("CA2010").FormulaArray = "=SUM(IF(FREQUENCY(IF(SUBTOTAL(3,OFFSET(E2:E2000,ROW(E2:E2000)-ROW(E2),0,1)),MATCH(""~""&E2:E2000,E2:E2000&"""",0)),ROW(E2:E2000)-ROW(E2)+1),1))"
End Sub
I tried breaking the array formula into two parts based on some guidance out there, but it still did not resolve the issue.
The reason for the error is that the R1C1 format version of your formula exceeds 255 characters (even though the A1 style version is much shorter than that) due to the relative references. If you use absolute references, the formula is short enough to be entered using FormulaArray; if you can't do that, you'll need to use the workaround of splitting the formula into sections so that you can use the Range.Replace method after entering a shorter version.
I've only been using VBA for a couple of weeks now so bear with me.
I'm trying to change a macro so that it reads from an array instead of a range. One of the sections I need to change uses .formulaR1C1 to run a vlookup, but im having a hard time trying to work out how this can be done with the array.
An example of this is the below line:
.Range("M2:L" & lastrow).FormulaR1C1 = "=VLOOKUP(RC[-1], Sheet2!R1C1:R4C10, 3, 0)"
I'm not too sure on whether I can set the value of an array to a formula, as I've done above, or if I have to maybe store the value as a String and then edit the value of the cell later when printing the column back on to the worksheet.
What I have so far is below:
For i = 2 To lastrow
arr(i, 13).FormulaR1C1 = "=VLOOKUP(RC[-1],Sheet2!R1C1:R4C10,3,0)"
Next
Thanks in advance!
Storing the value as a string would certainly be a valid option. Simply write the formula in your array, presuming it is of Variant / String type, and when you put the data back into a worksheet you can use .FormulaR1C1 on a Cell (Range) object to apply it as a formula.
arr(i, 13) = "=VLOOKUP(RC[-1],WMSPAM!R1C1:R4C10,3,0)"
...
Range("M2").FormulaR1C1 = Arr(1,13)
I believe this approach is likely the most effective and most easily maintained for you. As you are learning and appear to be curious of what is possible, here are a couple more examples of how you could approach this, with some further explanation.
.FormulaR1C1 is a Range object method and so the only way it could be called on an Array item would be if that item was a Range object.
Dim arr(0 To 10) As Range
Set arr(0) = Range("A1")
arr(0).FormulaR1C1 = "=2+2"
Note that as Ranges are an Object (of reference type), this operation will directly effect the Range specified in the array. In the above example, the formula "=2+2" will be placed into cell A1. You can learn more about the difference between Reference and Value types here.
If your array contains only values, the other way to achieve what you need is to use the WorksheetFunction object. With this object you can access the formula functions, that you would use in worksheet, within VBA.
WorksheetFunction.VLookup(Arg1, Arg2, Arg3, Arg4)
As with anything in writing code the WorksheetFunction methods take some trial and error to get them to work how you would expect, but in my experience these specifically can be a tricky to implement, there are though some cases where they can be very useful!
You can read more about the VLookup method here.
You may try to use .Offset():
Sub Test()
lastrow = 11
With Sheets(1)
Set Rng = .Range("M2:L" & lastrow)
End With
For i = 0 To Rng.Rows.Count - 1
Rng.Offset(i, 12).FormulaR1C1 = "=VLOOKUP(RC[-1],Sheet2!R1C1:R4C10,3,0)"
Next
End Sub
I'm not sure what you are asking. Your first code line writes a formula to a two-column range in the most efficient way there is already, your second snippet shows the less efficient way of doing it one cell at the time. If the goal is to use the vlookup to fill cells and then dispose of the formula, one efficient way is this:
.Range("M2:L" & lastrow).FormulaR1C1 = "=VLOOKUP(RC[-1], Sheet2!R1C1:R4C10, 3, 0)"
.Range("M2:L" & lastrow).Value2 = .Range("M2:L" & lastrow).Value2
I'm trying to get the values from an array formula into VBA as an array. Simple example: I have a cell (let's say D1) which has an array formula in it such as
=A1:A10*B1:B10
when I highlight this on the spreadsheet and press F9 I'll get an array of 10 numbers, say, ={5;12;15;24;25;24;42;40;54;70}
I want to be able to store these values in a VBA array: a(0)=5, a(1)=12, a(3)=15 etc; you get the idea.
Tried hunting for an answer on this one, but can't find anything relevant even on MSFT. Lots of answers about how to go the other way from VBA to the worksheet range (I know that one) but not this way. Looked at trying to do it via a ParamArray (the number of elements won't be fixed), by assigning directly to a undimensioned array and via EVALUATE(range) but I can't get any of these to work. I feel I must be missing something obvious.
Not sure what you have tried already. But Evaluate should work.
If I have the following:
The code:
Sub getArrayFormulaResult()
sFormula = Range("D1").FormulaArray
aResult = Evaluate(sFormula)
MsgBox Join(Application.Transpose(aResult), ",")
End Sub
will result in:
try this
Dim var as variant
var=Worksheets("MySheet").Evaluate(Worksheets("MySheet").Range("D1").formula)
Note you should use Worksheet.Evaluate to ensure this works when Mysheet is not the active sheet. The result will always be a 2_D array (with one column for your example array formula)
Possible to Run Goal Seek on array elements within VBA, instead of an Excel sheet range?
I have an array that takes initial values from an excel input sheet, does many calculations, and prints values back into a report region on an excel sheet; the output is roughly 200 rows x 28 columns of calculated values. I used to do this with formulas in every cell, but it was very, very slow. I converted to an all-vba Sub that does the calculations quickly and pastes the finished values into the report range in excel.
The problem is that I also need to run Goal Seek on various cells and Excel can't do it on a cell that just has a value, it needs a cell with a formula. With my fancy, efficient array, I can't goal seek anymore!!!!!
Is there a way to run some version of Goal Seek NOT on excel sheet ranges but on array members, like on MyArray(107,23) by testing an input value that is actually on the excel sheet, like Range("B2")? What would that code look like?
The first subroutine uses Range while the second uses Array instead. The goal here is 0.
First subroutine :
Sub GoalSeekWithRange()
Dim i As Long
For i = 1 To 10
Range("C" & i).GoalSeek Goal:=0, ChangingCell:=Range("A" & i)
Next
End Sub
Second subroutine :
Sub GoalSeekWithArray()
Dim arGoal As Variant
Dim arChanging As Variant
With ThisWorkbook.Sheets("MySheet")
Set arGoal = .Range("C1:C10")
Set arChanging = .Range("A1:A10")
End With
Dim i As Long
For i = 1 To 10
arGoal(i, 1).GoalSeek Goal:=0, ChangingCell:=arChanging(i, 1)
Next
End Sub
To avoid headaches, remember an array of range has two dimensions
Probably, you will have to adapt these codes to fit your specific need
I have been told there is a way of storing data in dynamic arrays which can then be referred to in a function.
I come from my recent answered question:Showing hidden column in another sheet
I am trying to find out how to store in a dynamic array which row (first array), column (second array) and sheet (third array) my code has to make action on.
I still haven't done arrays in my class, I'm just guessing it is a dynamic one for what I have researched. Do you think this could be done in the same array using different dimensions?
(Edited ->) -- Being more specific: I am looking for a way to store a number of specific rows(or columns) of a specific sheet to then (in a loop I guess) run my function for each element.
I have read the basic documentation (https://msdn.microsoft.com/en-us/library/aa716275(v=vs.60).aspx) and looked for similar posts here but I can't find it. If someone can point out what I should do or read to achieve this I can try and do it myself if you believe it's better.
Edited:
I think I am doing some progress, but I still don't know how to refer to a the sheet within the range.
Would this do the job (if I didn't need sheet referring)?
Public Sub Test()
Dim Rng As Range
Dim Area As Range
Set Rng = Range("A1:A10,B1:B20,G1:G3")
For Each Area In Rng.Areas
Area.Hidden = True
Next Area
End Sub
You can manage that with a single array of Range because the range refer to:
The sheet
The row
The Column
Dim array() as Range
...
' Store with
set array(i) = worksheet.Range(a, b)
...
' Read with
set range = array(i)
The link to msdn in your question explain how to manage Dynamic Arrays
update
The problem in your code is you not refer the worksheet you want.
If no worksheet is indicate, in the best case an error is thrown, in the worst case it takes the "Activesheet" (yes, an error is a better case then work on you don't know what).
Consider you know the name of the sheet (or the position of it), you can pass it in parameters
Public Sub Test(byval sheetname as string)
' First solution: declare a worksheet variable referencing to your worksheet
dim ws as worksheet, rng as range, area as range
set ws = Worksheets(sheetname)
Set rng = ws.Range("A1:A10,B1:B20,G1:G3")
For Each area In rng.Areas
area.Hidden = True
Next Area
' You could replace the dim of ws by a With Worksheets(sheetname)
' and work with .Range() instead
End Sub