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)
Related
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.
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 am trying to populate different portions of an array based on different locations within a spreadsheet.
For example
Dim prices(50) as double
prices(0, 1, 2) = Range("i35", "i38")
prices(3,4,5,6,7,8) = Range("b7","b12")
I'm getting a wrong number of dimensions error, because I'm assuming you have to populate the whole thing at once. Is there another syntax to do this better, or is it just a limitation of VBA?
Possibly a for each loop? But that doesn't really help since there are a lot of different ranges.
Thanks for your help
It looks like you are trying to tell VBA that the list of numbers in the parenthesis of the array are positions within an array that will receive multiple items.
That's not what it is. Instead, you can only do one at a time. For example:
Dim prices(50) as double
' My range syntax might be wrong here.
prices(0) = Range("i35", "i35")
prices(1) = Range("i36", "i36")
prices(2) = Range("i37", "i37")
prices(3) = Range("i38", "i38")
..etc. Or, if you're new to programming, you'll find this really cool:
for CounterVariable = 0 to 3
prices(CounterVariable) = Range("i" & 35 + CounterVariable)
next CounterVariable
To Wit ...
an array defined like Dim prices(50) will have one 'dimension', like a straight line.
Picture one row in a spreadsheet, 50 columns long.
If you said Dim prices(50,60) you would have a 2-dimensional array, like a cartesian plane (x,y) or a 50x60 cell spreadsheet where the first number is like the letters, the second, like the numbered rows.
Some languages support 3-dimensional arrays - VariableName(x,y,z). Don't know if VBA does
Therefore, using commas in parenthesis after an array is supported by VBA
BUT it means something completely different than you were hoping (and you can't change that): the values for the dimensions.
So your last line of code is looking for some value in a 6-dimensional universe! So we've got, height, width, depth, time, tesseract, and uh, you've beat me there!!!
I am making some VBA code to help me do the following:
Paste a list of all named ranges
Loop through the list and copy/select ranges based on the list
Each selection will be pasted on another sheet given an address reference with a certain offset from that address
I am pretty new to VBA so I have put together some code that I think will do the trick but I am getting run time errors. Could someone help me troubleshoot or provide suggestions?
My code is here:
Sub RangeLoop()
Sheets("RANGEMATCH").Select
Range("A1").ListNames
Dim columnrange As Range
Dim m As Long
Dim address As Range
Set columnrange = Sheets("RANGEMATCH").Range("A:A").SpecialCells(xlConstants)
With columnrange
For m = 1 To columnrange.Areas.Count
Set address = Sheets("RANGEMATCH").Range(.Areas(m).Cells(1, 7).Value)
Range(m).Copy Sheets("ETIE").Range(address.Offset(1, 10))
Next
End With
End Sub
Here is an example workbook of what I am working with:
https://docs.google.com/spreadsheet/ccc?key=0AodOP_8DnJnFdHJoQ0xBM3JUUGJxT3EyRXN0T2ltUmc&usp=sharing
Any suggestion are appreciated.
The Range() function expects a string variable. Either the name of a range or a cell reference like "A1"
Range(m).Copy Sheets("ETIE").Range(address.Offset(1, 10))
m is a number so that won't work. You'll need to reference the thing that you want to copy. I think that might just be your address object that you set in the line before:
address.Copy Sheets("ETIE").Range(address.Offset(1, 10))
Excel-VBA 2007 appears to have a 64k limit on the size of arrays passed as arguments.
Is anyone aware of a fix or work-around?
Here's the code:
Public Function funA(n)
Dim ar()
ReDim ar(n)
funA = ar
End Function
Public Function funB(x)
funB = UBound(x)
End Function
From Excel:
=funB(funA(2^16-1)) '65536 as expected
=funB(funA(2^16)) 'Gives a #VALUE
Looking inside, funA() works fine but, passed to funB, the argument x is an Error 2015.
I think it's a limitation of the spreadsheet cell itself, rather than VBA. Excel can pass arrays bigger than 2^16 between functions, but apparently it can't contain an array of that size within a cell.
As an experiment, highlight funA(2^16) in the cell formula and hit F9 - it'll give you a '#VALUE!' error.
Because the formula has already calculated the result of funA before it initiates funB, it's then trying to run funB on a function that's already calculated to an error.
It seems a work-around like the one Brad posted (i.e. a third function that calculates funB(funA(n)) within itself) keeps the cell out of the equation until the calculation's completed, so it works fine.
Because single-dimensional arrays are passed back to Excel as a row of columns you have hit the Excel 2007 limit on the number of columns (64K).
If you make your array 2 dimensional and return as rows it should work:
Public Function funA(n)
Dim ar()
ReDim ar(n,1)
funA = ar
End Function
Alternatively you can use Transpose to rotate the array from a row to a column, but this is probably less efficient than creating a 2-dimensional array in the first place.
This seems to be as close to a work around as I can find. Do the inter-function calls from VBA
If you make something like this
Public Function funBA(n As Variant) As Variant
funBA = funB(funA(n))
End Function
it seems to work up to n=2^24=2^8^3 (which doesn't look like any data type break point in VBA which is where the hang up is, but that's a pretty big array)
It's not a VBA issue because you can run this and get no errors
Public Sub test()
x = funB(funA(2 ^ 16 - 1))
y = funB(funA(2 ^ 16))
Debug.Print x; y
End Sub
It seems to be an issue passing it back to Excel - not much documentation but it seems to be a Excel limit.
Here is another link but no solution WorksheetFunction array size limit
and another
http://answers.microsoft.com/en-us/office/forum/office_2007-excel/passing-arrays-to-excel-worksheet-functions-in/56d76732-9a15-4fd2-9cad-41263a4045d4