VBA Create an array with numbers 1 through some calculated value - arrays

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))), "/", "\")

Related

Proper way to return elements of (ThisWorkbook.name) before the element of Format (Date)

I have file with name All PM 7.6 10-Jun v2 , All PM 7.6 is a dynamic name and (10-Jun) is static name formulated using Format(Date, "DD-MMM")
I want to get these elements (All PM 7.6) ,I tried the following:
Dim arrname, strExisting As String
arrname = Split(ThisWorkbook.name, ".")
strExisting = arrname(0) & "." & arrname(1)
I think using arrname(0) & "." & arrname(1) is not the proper way to get it ,as if this parts of name changed then I need to modify the code again.
In advance, thanks for all your help.
Since you did not clarify (at least, for me) what is to be returned, please use the next function to extract the date string:
Function ExtractDateStr(strName As String) As String
Dim arr: arr = Split(strName, " ")
Dim strD As String: strD = arr(UBound(arr) - 1)
ExtractDateStr = strD
End Function
It can be used in the next way, to return the prefix before the date string or each element up to it:
Sub testExtractWbNameElements()
Dim x As String, strPrefix As String
x = "All PM 7.6 10-Jun v2.xlsx"
Debug.Print ExtractDateStr(x)
strPrefix = left(x, InStr(x, " " & ExtractDateStr(x)) - 1)
Debug.Print strPrefix 'the string before the date part
Dim arrElem
arrElem = Split(strPrefix, " ") 'each elements up to the date part, in an array:
Debug.Print UBound(arrElem), Join(arrElem, "|") 'just proving the return...
End Sub
The above solution assumes that the elements before the date part may be different in terms of number. If only three, as in your example, the solution can be simpler..
Edited:
If the first elements to be returned will always be three, use the next simpler way:
Sub testSplitSpecElemNo()
Dim x As String, arr
x = "All PM 7.6 10-Jun v2.xlsx"
arr = Split(x, , 4, 0) '4 means how many elements to return. First three and the last one (the rest all toghether) like the foourth
arr(UBound(arr)) = "$##%&" 'characters not very probable to exist like such a group in the other array elements...
arr = filter(arr, arr(UBound(arr)), False) 'eliminate the last global one
Debug.Print Join(arr, "|")
End Sub

Store data by using FILTER Function within VBA [duplicate]

I'm trying to make a function MonstersInLevel() that filters the second column of my "LevelMonsters" named range based on the value of the first column. The range's first column represents a game level ID and the second column represents a monster ID that appears in that level. Here's what my range looks like.
If I call MonstersInLevel(2) I expect the function to return a range consisting of "2", "3" and "4".
Function MonstersInLevel(level As Integer) As Range
MonstersInLevel = Application.WorksheetFunction.Filter(Range("LevelMonsters").Columns(2), Range("LevelMonsters").Columns(1) = level)
End Function
I get:
A value used in the formula is of the wrong data type
I'm using the FILTER function as I would as an Excel formula. I assume there's some difference in the Excel and VBA syntax for FILTER's criteria.
Just encountered this problem myself and wanted to post my workaround.
We need to return an array of True/False to the worksheet function. To do this I created a Function that takes a 2D array, the column wanted and the value to compare. It then returns a 2d single column array of the necessary True/False.
Function myeval(arr() As Variant, clm As Long, vl As Variant) As Variant()
Dim temp() As Variant
ReDim temp(1 To UBound(arr, 1), 1 To 1)
Dim i As Long
For i = 1 To UBound(arr, 1)
temp(i, 1) = arr(i, clm) = vl
Next i
myeval = temp
End Function
So in this particular case it would be called:
Function MonstersInLevel(level As Integer) As Variant
MonstersInLevel = Application.WorksheetFunction.Filter(Range("LevelMonsters").Columns(2), myeval(Range("LevelMonsters").Value, 1, level),"""")
End Function
Avoid type mismatch in Worksheetfunction via VBA
Keeping in mind that the 2nd argument reflects a dynamic matrix condition
based entirely on â–ºworksheet logic (returning an array of 0 or 1 cell values /False or True])
it seems that you have
to execute an evaluation at least within this argument and
declare the function type (explicitly or implicitly) as Variant
Function MonstersInLevel(level As Integer) As Variant
'' Failing assignment:
' MonstersInLevel = Application.WorksheetFunction.Filter(Range("LevelMonsters").Columns(2), _
' Range("LevelMonsters").Columns(1) = level _
' )
MonstersInLevel = Application.WorksheetFunction.Filter( _
Range("LevelMonsters").Columns(2), _
Evaluate(Range("LevelMonsters").Columns(1).Address & "=" & level) _
)
End Function
...or to evaluate the complete function
Function MonstersInLevel(level As Integer) As Variant
Dim expr As String
expr = "=Filter(" & _
Range("LevelMonsters").Columns(2).Address & "," & _
Range("LevelMonsters").Columns(1).Address & "=" & level & _
")"
'Debug.Print expr
MonstersInLevel = Evaluate(expr)
End Function
Example call writing results to any target
Dim v
v = MonstersInLevel(2)
Sheet1.Range("D2").Resize(UBound(v), UBound(v, 2)) = v
Of course it would be possible as well to write .Formula2 expressions programmatically, even splitting into spill range references.
Addendum ........... //as of Jan 10th
Backwards compatible workaround via VBA.Filter()
"If you guys know any other VBA function that would be more appropriate
than Application.WorksheetFunction.Filter I'd be ok."
In order to provide also a backwards compatible alternative,
I demonstrate the following approach using the classic (VBA.)Filter() function (see section [3]) based upon
prior matching results (see [1]).
Note that Application.Match() comparing two (!) array inputs
delivers a whole array of possible findings (instead of a single result as most frequently executed).
Non findings are identified by IsError() values of -1; adding +1 results in a set
of zeros and ones. Section [2] enters corresponding data for positive findings.
Eventually non-findings (i.e. 0or zero) are removed by a tricky negative filtering.
Function getLevels()
Function getLevels(rng As Range, ByVal level As Long)
'Site: https://stackoverflow.com/questions/65630126/how-to-remove-only-the-duplicate-row-instead-of-removing-all-the-rows-that-follo
'[0] get datafield array
Dim v, v2
v = Application.Index(rng.Value2, 0, 1) ' 1st column
v2 = Application.Index(rng.Value2, 0, 2) ' 2nd column
'[1] check data (with Match comparing 2 arrays :-)
Dim results
results = Application.Transpose(Application.Match(v, Array(level), 0))
'[2] rebuild with False/True entries
Dim i As Long
For i = 1 To UBound(results)
results(i) = IsError(results(i)) + 1 ' 0 or 1-values
If results(i) Then results(i) = v2(i, 1) ' get current value if true
Next i
'[3] remove zeros (negative filtering)
results = Filter(results, "0", False)
'[4] return results as vertical 1-based array
getLevels = Application.Transpose(results)
End Function
Example call
Const LVL = 2 ' define level
With Sheet1 ' change to project's sheet Code(Name)
'define data range (assuming columns A:B)
Dim rng As Range
Set rng = .UsedRange.Resize(, 2)
'function call getLevels()
Dim levels
levels = getLevels(rng, level:=LVL)
'write to target
.Columns("I:I").Clear
.Range("I2").Resize(UBound(levels), 1) = levels
End With
Solution without any supporting VBA function:
Function MonstersInLevel(level As Integer) As Variant
With Application.WorksheetFunction
MonstersInLevel = .Filter(Range("LevelMonsters").Columns(2), _
.IfError(.XLookup(Range("LevelMonsters").Columns(1), level, True), False))
End With
End Function
XLookup returns an array of #N/A or True. IfError replaces errors with False. Finally, the Filter function receives an array of booleans as the second parameter.
EDIT
Removed the IfError function thanks to #ScottCraner:
Function MonstersInLevel(level As Integer) As Variant
With Application.WorksheetFunction
MonstersInLevel = .Filter(Range("LevelMonsters").Columns(2), _
.XLookup(Range("LevelMonsters").Columns(1), level, True, False))
End With
End Function
I couldn't resolve your question but as I did some testing on the subject trying to do so, I thought I'd share my findings:
Based on this Microsoft community post, or at least the answers there, it seems you will need to loop through the output in one way or another...
That question seems to want to achieve the same as what you are wanting to do (I think?).
On the other hand, I have never used the WorksheetFunction.Filter method, and the closest I could get it to working was like so:
Here is my sample data - RangeOne is Column A and RangeTwo is Column B. I have used the =FILTER() function in cell C1 evaluating the input in D1 for reference of expected results. Naturally this function is working as expected! The VBA routine is outputting to Columns E, F and G.
Sub TestFilterFunction()
Dim TestArray As Variant
Range("E1:E3") = Application.Filter(Range("RangeTwo"), Range("RangeOne"), Range("D1"))
Range("F1:F3") = Application.Filter(Range("RangeTwo"), Range("RangeOne") = Range("D1")) 'Runtime Error 13
Range("G1:G3") = Application.Filter(Range("RangeTwo"), Range("RangeOne"))
TestArray = Application.Filter(Range("RangeTwo"), Range("RangeOne"), Range("D1"))
TestArray = Application.Filter(Range("RangeTwo"), Range("RangeOne") = Range("D1")) 'Runtime Error 13
TestArray = Application.Filter(Range("RangeTwo"), Range("RangeOne"))
Range("H1:H3") = Application.Filter(Range("RangeTwo", "RangeOne"), Range("RangeOne"), Range("D1"))
TestArray = Application.Filter(Range("A1:B9"), Range("RangeOne"), "2")
End Sub
Column E returned the first 3 values from RangeTwo.
Column F has not been populated - This is because that line threw the Runtime error 13 - Type Mismatch
Column G returned the first 3 values from RangeTwo.
Column H returned the first 3 values from "A1:B9" (both ranges together) - specifically the first 3 values of column A.
I thought this was odd so I threw in an array to assign the values to rather than directly to the worksheet;
The first TestArray line and the third TestArray line both populated the array with the entire RangeTwo values;
I realised with the syntax of the first and third attempt at the WorksheetFunction.Filter, the entire range is returned (that being the first argument - Arg1 - range), but when trying to include the = Range("D1") , it returns the Type Mismatch error.
The final TestArray attempt being the same syntax as the Column H test, returned both columns in a 2D array (now TestArray(1 To 9, 1 To 2)).
I should note I couldn't find any documentation at all on WorksheetFunction.Filter so I'm assuming it does follow the same syntax as the Excel Sheet Function has.
If I find anything more on this topic I'll come back and edit it in, but for now it's looking like perhaps a solution using either loops or Index/Match functions also will need to happen to have the data returned in VBA.
I thought about perhaps writing the sheet formula to a cell and then grab that into an array or something but Excel inserts # into it now which only returns a single cell result, i.e.
Range("J1").Formula = "=FILTER(B1:B9, A1:A9 = D1)"
Would return in J1:
=#FILTER(B1:B9, A1:A9 = D1)
Which with our sample data, would only return 2 in J1 as opposed to the expected/desired 2, 3 and 4 in J1:J3.
I can't work out a way to remove the # as it is applied when the function is written to the cell unfortunately, but hopefully any of the above helps someone find a solution.
Just some comments to help you out.
If you are using the new FILTER() function from either a worksheet cell or within some VBA code, the first argument should be a range and the second argument should a a Boolean array. (if you don't enter something that can evaluate to a Boolean array, VBA may complain the the data type is wrong)
You would be best served (in VBA) if you:
explicitly declared a 2 dimensional, column-compatible, Boolean array
filled the array
used the array in the function call
Here is a super simple example. Say we want to filter the data from A1 to A6 to remove blanks. We could pick a cell and enter:
=FILTER(A1:A6,A1:A6<>"")
Looks like:
Now we want to perform the same activities with a VBA sub and put the result in a block starting with B9. The code:
Sub SingleColumn()
Dim r As Range, wf As WorksheetFunction, i As Long
Dim arr, s As String, dq As String, boo, rc As Long
Set wf = Application.WorksheetFunction
Set r = Range("A1:A6")
rc = r.Rows.Count
ReDim boo(1 To r.Rows.Count, 1 To 1) As Boolean
i = 1
For Each rr In r
If rr.Value = "" Then
boo(i, 1) = False
Else
boo(i, 1) = True
End If
i = i + 1
Next rr
arr = wf.Filter(r, boo)
MsgBox LBound(arr, 1) & "-" & UBound(arr, 1) & vbCrLf & LBound(arr, 2) & "-" & UBound(arr, 2)
Range("B9").Resize(UBound(arr, 1), UBound(arr, 2)) = arr
End Sub
Result:
On Excel version 15.0 (2013), I don't see Application.WorksheetFunction.Filter (tried with Show Hidden Members):
So maybe this is a newer function in later versions ?
My top Google search directs me to this question ;)
So, my answer is to avoid the function primarily from the point of view of backwards compatibility.
Alternate code options presented below returning e.g. a Range and a Variant.
Input:
Code:
Option Explicit
Sub Test()
Dim rngInput As Range
Dim rngFiltered As Range
Dim varFiltered As Variant
Dim varItem As Variant
Set rngInput = ThisWorkbook.Worksheets("Sheet1").Range("A2:B10")
' as range
Debug.Print "' Output as Range"
Set rngFiltered = MonstersInLevel_AsRange(rngInput, 2, 1, 2)
Debug.Print "' " & rngFiltered.Address ' expect B5, B6, B8
Debug.Print "' ---------------"
' as variant
Debug.Print "' Output as Variant"
varFiltered = MonstersInLevel_AsVariant(rngInput, 2, 1, 2)
For Each varItem In varFiltered
Debug.Print "' " & varItem ' expect 3, 4, 5
Next varItem
Debug.Print "' ---------------"
End Sub
Function MonstersInLevel_AsRange(rngToFilter As Range, _
ByVal lngLevel As Long, _
ByVal lngColIxToFilter As Long, _
ByVal lngColIxForValue As Long) As Range
Dim rngResult As Range
Dim lngRowIndex As Long
Dim lngResultIndex As Long
Set rngResult = Nothing
For lngRowIndex = 1 To rngToFilter.Rows.Count
If rngToFilter.Cells(lngRowIndex, lngColIxToFilter) = lngLevel Then
If rngResult Is Nothing Then
Set rngResult = rngToFilter.Cells(lngRowIndex, lngColIxForValue)
Else
Set rngResult = Union(rngResult, rngToFilter.Cells(lngRowIndex, lngColIxForValue))
End If
End If
Next lngRowIndex
Set MonstersInLevel_AsRange = rngResult
End Function
Function MonstersInLevel_AsVariant(rngToFilter As Range, _
ByVal lngLevel As Long, _
ByVal lngColIxToFilter As Long, _
ByVal lngColIxForValue As Long) As Variant
Dim varResult As Variant
Dim lngRowIndex As Long
Dim lngResultIndex As Long
lngResultIndex = 0
ReDim varResult(0)
For lngRowIndex = 1 To rngToFilter.Rows.Count
If rngToFilter.Cells(lngRowIndex, lngColIxToFilter) = lngLevel Then
lngResultIndex = lngResultIndex + 1
ReDim Preserve varResult(1 To lngResultIndex)
varResult(lngResultIndex) = rngToFilter.Cells(lngRowIndex, lngColIxForValue)
End If
Next lngRowIndex
MonstersInLevel_AsVariant = varResult
End Function
Test output:
' Output as Range
' $B$5:$B$6,$B$8
' ---------------
' Output as Variant
' 3
' 5
' 4
' ---------------
Based on Christian Buses answer (https://stackoverflow.com/a/65671334/16578424) I wrote a generic function to use the FILTER-function.
It returns a one-dimensional array with the filtered values.
Public Function getFILTERValuesFromRange(rgResult As Range, rgFilter As Range, varValue As Variant) As Variant
If rgResult.Columns.count > 1 Or rgFilter.Columns.count > 1 Then
Err.Raise vbObjectError + 512, , "Only ranges with one column are allowed."
ElseIf rgResult.Rows.count <> rgFilter.Rows.count Then
Err.Raise vbObjectError + 512, , "Both ranges have to be of the same size."
End If
Dim arr1 As Variant
With Application.WorksheetFunction
arr1 = .filter(rgResult, .XLookup(rgFilter, varValue, True, False))
End With
getFILTERValuesFromRange = getOneDimensionalArrayFromRangeArray(arr1)
End Function
Private Function getOneDimensionalArrayFromRangeArray(arr1 As Variant) As Variant
Dim arr2 As Variant
ReDim arr2(LBound(arr1, 1) To UBound(arr1, 1))
Dim i As Long
For i = 1 To UBound(arr1, 1)
arr2(i) = arr1(i, 1)
Next
getOneDimensionalArrayFromRangeArray = arr2
End Function

Excel VBA: Get Minimum out of 1 Dimension in Multi Dimensional Array

for work, I need to adjust some prewritten VBA code. But I am rather a beginner, thus it is quite challenging for me.
The code creates a 2D array called Targets. It spans by (a variable number of ) KPIs and for each KPI the values for 10 years (fix number). E.g.:
KPI 1 year_1 year_2 ... year_10
KPI 2 year_1 year_2 ... year_10
... ... .... ... ..... ... .... ... ..... ... ...
KPI n year_1 year_2 ... year_10
I now need to calculate the minimum per KPI line (1D array).
My ugly working code:
WorksheetFunction.Min(Targets(k, 0), Targets(k , 1), Targets(k, 2), Targets(k, 3), Targets(k , 4), Targets(k , 5), Targets(k, 6), Targets(k, 7), Targets(k, 8), Targets(k , 9))
Where k is directing to the correct KPI.
How can I make it work such that it basically takes the entire line without me having to direct the code to each specific cell? (e.g. Targets (k,:) or Targets (k, 0 to 9))
Bonus question: Some values within these arrays are zero as they are tbd. Those are supposed to be excluded from the minimum. So I need the Minimum > zero. Can you figure that out too?
It probably is super easy. But I cannot seem to make it work.
Thanks so much in advance!
Private Sub this()
Dim Targets As Variant
Dim minValuePerRow As String
minValuePerRow = ""
Targets = ThisWorkbook.Sheets("Sheet3").UsedRange
For i = LBound(Targets, 1) To UBound(Targets, 1)
For j = LBound(Targets, 2) To UBound(Targets, 2)
If (Targets(i, j) <> 0 Or Targets(i, j) <> "") And minValuePerRow = "" Then minValuePerRow = Targets(i, j)
If Targets(i, j) <> 0 And Targets(i, j) < minValuePerRow Then
minValuePerRow = Targets(i, j)
End If
Next j
Debug.Print ; i
Debug.Print ; minValuePerRow
minValuePerRow = ""
Next i
End Sub
EDIT
Reworked and tested it. This should be more than plenty to help you adjust to your needs.
This doesn't address the second part of your question about excluding zeros but...
Given a 2-D array (such as you might get from a worksheet range using Value), you can use Application.Index to get a "slice" of that array:
Sub Tester()
Dim arr, slice
arr = Range("A1:C3").Value
'get a "row"
slice = Application.Index(arr, 1, 0)
Debug.Print Join(slice, "-") '>> 1-2-3
'get a "column" (note use of Transpose here)
slice = Application.Transpose(Application.Index(arr, 0, 1))
Debug.Print Join(slice, "-") '>> 1-4-7
'col 2...
slice = Application.Transpose(Application.Index(arr, 0, 2))
Debug.Print Join(slice, "-") '>> 2-5-8
Debug.Print Application.Min(slice) '>> 2
End Sub
Worth noting that the performance of this approach is kind of bad though: Return Index of an Element in an Array Excel VBA
If the array size is too large, you'll find this to be very slow. It uses the Evaluate method to return the minimum for each row. However, you'll notice that I've included a function that makes those target values available to the Evaluate Method. Also, you'll notice that Targets is declared at the module level.
Dim Targets As Variant
Public Function Values() As Variant
Values = Targets
End Function
Sub test()
Dim i As Long
Targets = Range("A1:J10").Value
For i = LBound(Targets, 1) To UBound(Targets)
Debug.Print Application.Evaluate("MIN(IF(INDEX(Values()," & i & ",0)>0,INDEX(Values()," & i & ",0)))")
Next i
End Sub
Hope this helps!

populating a string array dynamically from a column of phrases in an excel sheet

I have 2 sheets. I am using a user-defined function in sheet 1, in which I want to use an array to compare some strings. The array is comprised of the contents of a column of cells in the second sheet (which is named "phrases.").
So (looking at it another way) in "phrases" I have 100 strings typed into column P, cells 3 to 102. And I want to put all of them into an array that i can use later.
Now, let me complicate it a little - my intent is that users of the spreadsheet will be able to add new content to column P, so that it may eventually be 500 cells or more. So I really want to populate that array dynamically.
Here's where i am - and it doesn't seem to be working:
Dim newarray() As String
Dim i As Long
Dim counter As Long
counter = 0
For i = 0 To 5000
If Worksheets("phrases").Cells(i + 3, 16).Value <> 0 Then
newarray(counter) = Worksheets("phrases").Range(i + 3, 16).Value
counter = counter + 1
End If
Next
Where am i going wrong?
Please note - I've tried this without .Value - didn't seem to work.
I've tried this with .Text instead of .Value - didn't seem to work.
I've tried CStr(Worksheets("phrases").Range(i + 3, 16).Value) and several variations - and it didn't seem to work.
I expect there is something simple I am missing here - but i have no idea what.
Dim newarray() As String
Dim i As Long
Dim lr AS Long
Dim counter As Long
lr = ActiveSheet.Range("P" & Rows.Count).End(xlUp).Row
counter = 0
For i = 1 To lr
If Worksheets("phrases").Range("P" & i).value <> 0 Then
Redim Preserve newarray(counter)
newarray(counter) = Worksheets("phrases").Range("P" & i).value
counter = counter + 1
End If
Next
First construct a comma-separated string. Then convert the string into an array using the Split() function.
You can make the array directly from the cells without having to loop at all using a single line of code, this will also capture anything that the user adds to the bottom of column P by using the Resize() method:
Sub SO()
stringArray = [P3:P102].Resize(Range("P" & Rows.Count).End(xlUp).Row - 2, 1)
'// Print each value in the array
For Each x In stringArray
Debug.Print CStr(x)
Next x
End Sub

Excel VBA - Shifting values of an array of numbers by a constant without looping

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

Resources