In a function I define my array like below but the function gives me #value when I use it in the worksheet. It works when I leave the part Worksheets("interestrates")., however, in the wrong sheet then. What can I do, to tell Excel to fill the array with values from the worksheet "interestrates"
array1 = Worksheets("interestrates").Range("a" & range1.Value & ":c" & range2.Value)
Assuming range1 and range2 are single cell Range objects which evaluate to an integer/long value, I believe this is your problem:
You have a multi-dimensional array (3 columns, and a varying number of rows to be determined by the maximum of range1 or range2). The number of rows doesn't really matter. The problem is that you cannot put an array of values in a single cell.
Long story short, you should certainly be able to assign to an array like you are doing, for example:
If your function is returning #Value! error, then there is some problem with the rest of your function, or with what you are expecting/attempting to do with the function.
Related
I have write bellow code, that prints 210 in immediate window.
Sub RangeToArr()
Dim data() As Variant
data = Range("Salary[EmpNum]").Value
Debug.Print UBound(data)
End Sub
When I using bellow, the Subscript out of range Run-time error message will displayed.
Sub RangeToArr()
Dim data() As Variant
data = Range("Salary[EmpNum]").Value
Debug.Print data(210)
End Sub
If data is an array, what is the problem, else, how can access a range values that assigned to an array, as above?
A range converted to an array will create a 2 dimensional array, if you try to return data(210) you are referencing it as if it's a single dimensional array. You can get the value from the 210th cell in the range by returning
data(210, 1)
I can only assume as to the reason why it forces a 2 dimensional array. My guess is because if your range included additional columns it would be 2 dimensional array. The act of creating a 2 dimensional array regardless even if you only have one column means the method for dealing with the data remains the same. There is an exception to this - If your range is a single cell, VBA will populate just the value as a single dimension.
To make sure your sample works, make sure you have 210 rows in your table sample.
In general, try something like this to get the idea of the arrays and ranges:
Crate a simple named range MyNamedRange with more than one column and more than one row
Put some values in it
Run this and see what you are getting in the immediate window:
Sub RangeToArr()
Dim arrVar As Variant
arrVar = Range("MyNamedRange")
Debug.Print arrVar(1, 2)
End Sub
Change the (1,2) values a bit to get the idea.
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)
I have a case in an Excel macro (VBA) where I'd like to dimension an array where the number of dimensions and the bounds of each dimension are determined at runtime. I'm letting the user specify a series of combinatorial options by creating a column for each option type and filling in the possibilities below. The number of columns and the number of options is determined at run time by inspecting the sheet.
Some code needs to run through each combination (one selection from each column) and I'd like to store the results in a multidimensional array.
The number of dimensions will probably be between about 2 to 6 so I can always fall back to a bunch of if else blocks if I have to but it feels like there should be a better way.
I was thinking it would be possible to do if I could construct the Redim statement at runtime as a string and execute the string, but this doesn't seem possible.
Is there any way to dynamically Redim with a varying number of dimensions?
I'm pretty sure there is no way of doing this in a single ReDim statement. Select Case may be marginally neater than "a bunch of If...Else blocks", but you're still writing out a lot of separate ReDims.
Working with arrays in VBA where you don't know in advance how many dimensions they will have is a bit of a PITA - as well as ReDim not being very flexible, there is also no neat way of testing an array to see how many dimensions it has (you have to loop through attempts to access higher dimensions and trap errors, or hack around in the underlying memory structure - see this question). So you will need to keep track of the number of dimensions, and write long Case statements every time you need to access the array as well, since the syntax will be different.
I would suggest creating the array with the largest number of dimensions you think you'll need, then setting the number of elements in any unused dimensions to 1 - that way you always have the same syntax every time you access the array, and if you need to you can check for this using UBound(). This is the approach taken by the Excel developers themselves for the Range.Value property - which always returns a 2-dimensional array even for a 1-dimensional Range.
As I understood your users can specify dimensions and their seize by filling in the excel-sheet. This means you have to get the last row containing a value and the last column.
Therefore, have a look at: Excel VBA- Finding the last column with data
Use Redim to change the array's size. If you want to keep some kind of entries use Redim Preserve
"Some code needs to run through each combination (one selection from
each column) and I'd like to store the results in a multidimensional
array."
To begin with, I would transpose desired Range object into a Variant.
Dim vArray as Variant
'--as per your defined Sheet, range
'this creates a two dimensional array
vArray = ActiveWorkbook.Sheets("Sheet1").Range("A1:Z300").Value2
Then you could iterate through this array to possible find the size and data you need, which you may save it to an array (with the dimensions) you need.
Little Background:
Redim: Reallocates storage space for an array variable.
You are not allowed to Redim an array, if you are defining an array with a Dim statement initially. (e.g. Dim vArray(1 to 6) As Variant).
UPDATE: to show explicitly what's allowed and what's not under Redim.
Each time you use Redim it resets your original Array object to the dimensions you are defining next.
There's a way to preserve your data using Redim Preserve but that only allows you to change the last dimension of a multidimensional array, where first dimension remains as the original.
I have a range with 170000 rows in it. I'm filtering column A for a single value and returning the corresponding values in column B.
I want these values to dump into an array so I can quickly toss them into a dictionary (with the key being the value I filtered column A with).
The problem is that SpecialCells(xlCellTypeVisible) is acting inconsistent.
If I do the same test on a smaller range, the values dump into the array just fine. But with a range as large as mine, it only returns the first value in the range. Also, I can use the same line to copy to another sheet. I just can't get it to populate the array.
foo = ws1.Range(tbl1Name & "[ID]").SpecialCells(xlCellTypeVisible)
Works with small ranges, but returns only the first result in a range as large as mine (less than 50 results.) foo becomes an array containing all the variables.
ws1.Range(tbl1Name & "[ID]").SpecialCells(xlCellTypeVisible).Copy ws2.Range("A1")
Works with the large range and copies all the relevant data successfully.
So my question: How do I populate the array without the extra step of copying to a blank worksheet when autofiltering a large table range? (Excel 2013)
EDIT: requires a reference to "Microsoft Forms 2.0 Object Library" (should be near the top of the list of available references). Or add a userform to your project and that will auto-add the reference (you can then remove the form...)
This should work for a single column:
Sub Tester()
Dim rng, txt As String, cb As New DataObject, arr
Set rng = ActiveSheet.Range("A2:A28").SpecialCells(xlCellTypeVisible)
rng.Copy
DoEvents
cb.GetFromClipboard
txt = cb.GetText
arr = Split(txt, vbCrLf)
Debug.Print LBound(arr), UBound(arr)
End Sub
If you had multiple columns you'd need to loop over each element of arr (splitting its value on tab) and transfer the values to a 2-d array.