I need to create a 2D array which is not intended to be updated, only read.
Reading this question, I found this possibility using evaluate:
Dim varData As Variant
varData = [{1, 2, 3; 4, 5, 6; 7, 8, 9}]
In my case, the number of values requires to split the assignment on several lines, e.g.
varData = [{value1, value2; _
...; _
valueM, valueN}]
However when using _ to split this assignment, VBA complains at the first line with:
Compile Error:
Missing end bracket
I've tried to find the explanation, but all examples seems to use only a single line. What is wrong?
Note: I'm trying to populate an array, not cells in a sheet.
I was thinking of this.
Dim A as Variant
A = Array(Array(1, 2), _
Array(3, 4), _
Array(5, 6))
Related
I'm writing a macro that will take a changing list of numbers (placed in an array), copy the equivalent slides from a powerpoint, and then paste the selected slides into another powerpoint (so if the numbers are 2, 5, and 7, the macro will copy/paste powerpoint slides 2, 5, and 7). I can make it work with individual array elements, but can't figure out how to pass all array elements at once into the selection. These are the relevant lines of code:
Dim NumberList() As Variant
NumberList= Range("A11", Range("A10").End(xlDown))
OriginalPowerpoint.Slides.Range(Array(NumberList(1, 1), NumberList(3, 1))).Copy
'this is the line I'm having trouble with
NewPowerpoint.Slides.Paste -1
The above code does work, but I want to pass the entire NumberList into Array() in the third line, as opposed to the current samples of NumberList(1,1) and NumberList(3,1). Just putting in "NumberList" or "NumberList()" doesn't work, and I'd really like to avoid making this a loop for efficiency reasons. Any advice would be greatly appreciated.
PowerPoint Slides Array feat 'write1D'
If your posted example works, this should do the trick (not tested).
Option Explicit
Sub PowerP()
Dim NumberList As Variant
NumberList = Range("A11", Range("A11").End(xlDown))
NumberList = write1D(NumberList)
OriginalPowerpoint.Slides(NumberList).Copy
End Sub
Function write1D(ColumnArray As Variant, _
Optional ColumnIndex As Long = 1) As Variant
Dim Source As Variant, i As Long
ReDim Source(UBound(ColumnArray) - LBound(ColumnArray))
For i = LBound(ColumnArray) To UBound(ColumnArray)
Source(i - LBound(ColumnArray)) _
= ColumnArray(i, LBound(ColumnArray, 2) + ColumnIndex - 1)
Next i
write1D = Source
End Function
Is there a way in Excel VBA to use Application.WorksheetFunction.Sumproduct to get the sumproduct of 2 array columns? For example, if A and B are two arrays each with 3 rows and 3 columns (VBA arrays, not Excel arrays), is there an easy way to get the sumproduct of the 3rd column of A with the 2nd column of B? If so, what is the syntax?
Thanks
While it might be tempting to try and use WorksheetFunction.SumProduct to do this, looping over a VBA array will be much faster than using worksheet functions. In a small test I got about a x40 performance improvement over the other posted answer.
This is a simple example of how you might do it. You should add validity checks on the inputs and error handling.
Function ArraySumProduct(aA As Variant, aB As Variant, col1 As Long, col2 As Long) As Variant
Dim i As Long
Dim dSumProduct
For i = LBound(aA) To UBound(aA)
dSumProduct = dSumProduct + aA(i, col1) * aB(i, col2)
Next
ArraySumProduct = dSumProduct
End Function
OK, seems as if WorksheetFunction.Index works with arrays of arrays also. So you can achieve this with a combination of WorksheetFunction.Index to get the 3rd and 2nd columns and WorksheetFunction.Transpose to get 1D-arrays of the columns and then WorksheetFunction.SumProduct.
Sub test()
aA = [{1,2, 3;4,5, 6;7,8, 9}]
aB = [{10, 11,12;13, 14,15;16, 17,18}]
'aA = Array(Array(1, 2, 3), Array(4, 5, 6), Array(7, 8, 9))
'aB = Array(Array(10, 11, 12), Array(13, 14, 15), Array(16, 17, 18))
aCol3of_aA = WorksheetFunction.Index(aA, 0, 3)
aCol2of_aB = WorksheetFunction.Index(aB, 0, 2)
aArr1 = WorksheetFunction.Transpose(aCol3of_aA)
aArr2 = WorksheetFunction.Transpose(aCol2of_aB)
dSumProduct = WorksheetFunction.SumProduct(aArr1, aArr2)
'= 3*11 + 6*14 + 9*17 = 270
MsgBox dSumProduct
End Sub
The Microsoft site suggests the following code should work:
Dim numbers = {{1, 2}, {3, 4}, {5, 6}}
However I get a complile error when I try to use it in an excel VBA module.
The following does work for a 1D array:
A = Array(1, 2, 3, 4, 5)
However I have not managed to find a way of doing the same for a 2D array.
Any ideas?
You can also use a shorthand format leveraging the Evaluate function and a static array. In the code below, varData is set where [] is the shorthand for the Evaluate function and the {...} expression indicates a static array. Each row is delimited with a ; and each field delimited with a ,. It gets you to the same end result as simoco's code, but with a syntax closer to your original question:
Sub ArrayShorthand()
Dim varData As Variant
Dim intCounter1 As Integer
Dim intCounter2 As Integer
' set the array
varData = [{1, 2, 3; 4, 5, 6; 7, 8, 9}]
' test
For intCounter1 = 1 To UBound(varData, 1)
For intCounter2 = 1 To UBound(varData, 2)
Debug.Print varData(intCounter1, intCounter2)
Next intCounter2
Next intCounter1
End Sub
The Microsoft site suggests...
This suggestion is for VB.NET but not VBA.
For VBA you were in the right direction. You can do this:
Dim A as Variant
A = Array(Array(1, 2), Array(3, 4), Array(5, 6))
Alternative via Application.Index()
Extending on Dmitriv Pavliv's use of a jagged array (and as alternative to Robin Mackenzie's short hand approach), you can go a step further by applying Application.Index() on this array of arrays (with identical number of elements each) - note the double zero arguments!:
Sub Get2DimArray()
Dim arr() As Variant
'a) build array of arrays (aka as jagged array)
arr = Array(Array(1, 2, 4), Array(4, 5, 6), Array(7, 8, 9))
'b) make it 2-dimensional
arr = Application.Index(arr, 0, 0)
End Sub
Results in
a 2-dim arr(1 To 3, 1 To 3), where
* Row 1 ~> 1|2|4
* Row 2 ~> 4|5|6
* Row 3 ~> 7|8|9
Related link
Further reading regarding Some pecularities of the Application.Index() function
So here you generate the array without anything on it, just by telling its dimensions.
Dimension is X+1 because 0 counts as a position in the array.
Dim MyArray(X, X) As Integer
Then you fill it by doing for exemple
MyArray (0,0) = 1
MyArray (0,1) = 2
MyArray (1,0) = 3
MyArray (1,1) = 4
...
And so on.
If you want a more convenient way of filling it you can use For Cycles if there is a inherent logic to the numbers you are filling it with.
In case the size is unknown until run time.
Dim nRows As Integer, nCols As Integer
...
Dim yourArray() As Integer
ReDim yourArray(1 to nRows, 1 to nCols) 'One base initialisation
'ReDim yourArray(0 to nRows - 1, 0 to nCols - 1) 'Zero base initialisation
Then you can initialise (or access) the grid as:
yourArray(1, 1) = ... 'set first cell
Question:
How can I create the following array without knowing the ending number before hand:
myArray = Array(0, 1, 2, 3, 4)
For example, I can do something similar in Python:
myList = range(ending_number)
As well as in Matlab:
myVector = 0:ending_number
More Detail:
I have a path being specified in an Excel worksheet that references a location on a Linux server. I want the user to only have to specify the path in terms that the Linux server understands, but also need to reference a location in terms that both the local Windows machine and the Linux server understands. The Linux server path is specified as
/home/shelf6/some/path/to/a/location/on/the/server
and the corresponding path in Windows is specified as
\\SB1\home_shelf6\some\path\to\a\location\on\the\server
I am currently converting from one to the other with the following commands:
WinJobLoc = Split(LinJobLoc, "/", -1, vbTextCompare)
WinJobLoc = "\\sb1\" & WinJobLoc(1) & "_" & WinJobLoc(2) & "\" & _
Join(Application.WorksheetFunction.Index(WinJobLoc, 0, _
Array(4, 5, 6, 7, 8, 9, 10, 11)), "\", vbTextCompare)
However, since I will only be able to know the length of the path from UBound(WinJobLoc), I don't know of an easy way to get the portion of the path following "shelf6."
Is there some way to do what I'm trying to do (i.e. without the hard-coded array), or is there an easier way to do the whole thing?
Consider:
Sub ArrayCreator()
Dim N As Long, i As Long
N = Application.InputBox(Prompt:="Enter a number", Type:=1)
ReDim myarray(0 To N) As Long
For i = 0 To N
myarray(i) = i
Next i
End Sub
I could be reading the question wrong but should this be enough:
Sub stringModify()
Dim LinJobLoc As String
Dim WinJobLoc As String
LinJobLoc = "/home/shelf6/some/path/to/a/location/on/the/server"
LinJobLoc = Replace(Right(LinJobLoc , Len(LinJobLoc ) - 1), "/", "\")
WinJobLoc = "\\SB1\" + Replace(LinJobLoc, "\", "_", , 1)
End Sub
But this does not answer your question to answer that you have two options:
One is you use a ReDim on the Array
The second option is to not use an array but instead use a collection.
Just re-read from the linux path, starting from an offset equal to the sum of the lengths of the elements you have already used, plus slashes, swapping path chars;
Dim ArrWinJobLoc() As String, WinJobLoc As String
ArrWinJobLoc = Split(LinJobLoc, "/")
WinJobLoc = "\\sb1\" & ArrWinJobLoc(1) & "_" & ArrWinJobLoc(2) & _
Replace$(Mid$(LinJobLoc, 3 + Len(ArrWinJobLoc(1)) + Len(ArrWinJobLoc(2))), "/", "\")
Is there a way to add a constant to an array of numbers in Excel VBA (Excel 2007) without looping?
For instance, I have the following array:
MyArray = (1,2,3,4,5)
And I want to obtain:
MyArray = (2,3,4,5,6)
Without looping.
On the Spreadsheet, if the values are in cells A1:A5, I can select B1:B5 and enter the array formula {=A1:A5+1}
MyArray = MyArray + 1
does not seem to work (Type mismatch error).
Any ideas?
Maybe this to increment the array by one:
v = Array(1, 2, 3, 4, 5)
With Application
v = .MMult([{1,1}], .Choose([{1;2}], v, 1))
End With
Update
Here's a more direct approach that also allows for incrementing 2D arrays
v = Application.Standardize(v,-1,1)
Worksheet function methods provide a large variety of math functions but the following were the only viable options i could find for basic arithmetic that support VBA arrays in arguments and return values:
(u-v)/w = .Standardize(u,v,w)
-u*v -w = .Fv(0,u,v,w)
int(u/v) = .Quotient(u,v)
Well, this is kind of cheating:
a = Array(1, 2, 3, 4, 5)
Range("a1:e1") = a
b = Evaluate("=a1:e1+1")
This is a user defined function which would do the trick for you. Just pass the reference cell and the increment value as arguments.
It doesn't handle cases where you have letters in the input cells so you'd need to create your own handling for that or ensure good data.
Function udf_IncrementArrayByVal(cellRef As Range, increment As Double)
Dim tempStr As String
Dim splitArray() As String
Dim cntr As Long
Dim arrayLength As Long
tempStr = Replace(Replace(cellRef(1, 1).Value, ")", ""), "(", "")
splitArray = Split(tempStr, ",")
For cntr = 0 To UBound(splitArray)
splitArray(cntr) = splitArray(cntr) + increment
Next cntr
tempStr = "(" + Join(splitArray, ",") + ")"
udf_IncrementArrayByVal = tempStr
End Function