When is ReDim necessary in dynamic arrays? - excel

I have a short question about ReDim-ming dynamic arrays - more precisely in which cases is it required?
I understand I need to ReDim Preserve array(x) As Variant when adding entries into the array. Adjusting/changing existing information in an array works well like: array(x) = "Added text " & array(x)
But are there any other cases when I need to worry about ReDim or maybe even other special requirements when handling dynamic arrays?
I'm writing a code which will include large dynamic arrays that get data added from many different sources before For-looping through it to write the date into a list on another sheet. I can't let an error pop up in the future because I missed something.

ReDimis used to change the size of an array. You can ReDim an array not initialized like this:
Dim arr() As Variant
x = 200
ReDim arr(1 to x)
You can also do this on initialized arrays:
Dim arr(1 to 2) As Variant
ReDim arr(1 to 5) <-- will delete previous stored values
ReDim Preserve arr(1 to 5) <-- will preserve previous stored values
Note that using the Preserve will only change the last dimension on multidimension arrays, so Dim arr(1 to 5, 1 to 2) if you want to keep your data using ReDim Preserve you can only change the second dimension from 1 to 2 to 1 to x.
Like Tom said, changing the size of your array in every loop will impact on the performance so you should first calculate the maximum size of your array and then dimension it, or dimension the size way over what you need and lastly redim it to your needs when you end.

Related

How do i manually declare a two dimentional array in vba? [duplicate]

This question already has answers here:
How to initialize a multidimensional array variable in vba for excel
(5 answers)
Closed 1 year ago.
in python it is possible to declare a list in a list for example like this
l=[[1,0,0],[0,1,0],[0,0,1]]
how do i do the same but in VBA excel
Declaring an array in VBA is different from initializing its contents (unlike python).
You declare a variable to be a 2D array of size N, M with
Dim a(1 to N, 1 to M) as Variant
but this creates a fixed sized array and not a dynamic array. It is better to declare an array as follows
Dim a() as Variant
ReDim a(1 to N, 1 to M)
and to fill the array with values you need a double loop, or assigning elements manually
a(1,1) = ...
a(1,2) = ...
Notice that I declared arrays that are 1-based, instead of 0-based (first element is a(1,1), and not a(0,0)) because when reading in a table from an Excel worksheet with
a = Range("A2").Resize(N,M).Value
Debug.Print a(3,1)
it creates such an array.
Note that it is possible to declare a dynamic array and fill it in with jagged form (array of arrays) using the following code
Dim a() as Variant
a = Array( Array(1,2,3), Array(4,5,6), Array(7,8,9) )
which you have access to in VBA with the following form
Debug.Print a(2)(0)
' 7
Notice that they arrays produced by the Array() command are 0-based with indexes varying between 0..N-1. Additionally, since the above is jagged array (array of arrays), the elements are accessed using sequential indexers as in a(i)(j) instead of a(i,j)
So it really depends on how you want to use the 2D array to decide how to best declare it.

Calculating expectation in table - With variable number of entries

Whilst I can correctly calculate Expectation in Excel, I am unsure of how to do so across a table when the number of entries is an unknown.
Currently, I am using the following formula which works: This is the example for 3 Entries,
=R11+(1-R11)*R12+((1-R11)*(1-R12)*R13).
I am using the large formula, to rank my percentages which go into R column but I am having to manually create the code for each subsequent entry and it is getting rather large. For example, the formula for 10 entries is :
=R11+(1-R11)*R12+((1-R11)*(1-R12)*R13)+((1-R11)*(1-R12)*(1-R13)*R14)+((1-R11)*(1-R12)*(1-R13)*(1-R14)*R15)+((1-R11)*(1-R12)*(1-R13)*(1-R14)*(1-R15)*R16)+((1-R11)*(1-R12)*(1-R13)*(1-R14)*(1-R15)*(1-(R16))*R17)+((1-R11)*(1-R12)*(1-R13)*(1-R14)*(1-R15)*(1-(R16))*(1-R17)*R18)+((1-R11)*(1-R12)*(1-R13)*(1-R14)*(1-R15)*(1-(R16))*(1-R17)*(1-R18)*R19)+((1-R11)*(1-R12)*(1-R13)*(1-R14)*(1-R15)*(1-(R16))*(1-R17)*(1-R18)*(1-R19)*R20)
Now, this is actually working. the issue is I would like to find a way to apply this in a table without re-ranking (or ranking this formulaically)
However, I'm not sure how this could be done. I have tried the sumproduct method, but it doesn't apply well to tables with a variable number of inputs, and I am well aware that I am running out of room past 10 entries.
I'm usually a dab hand with Excel - but this has truly got me stumped.
You can use this:
Function lkjlkj(rng As Range) As Double
Dim arr()
arr = rng.Value2
Dim i As Long
For i = 1 To UBound(arr, 1)
Dim temp As Double
temp = arr(i, 1)
Dim j As Long
For j = 1 To i - 1
temp = temp * (1 - arr(j, 1))
Next j
lkjlkj = lkjlkj + temp
Next i
End Function

Is there a function in Excel that removes duplicate strings from within a cell?

The UDF and other solutions offered in other questions do not solve this problem. Perhaps it is the length of the strings, and then number of duplicates in my problem. (All numbers, separated by commas, 13 digits long, 2 to 3 unique numbers repeated approximately 20-40 times in a single cell.)
I reviewed the answers to this question but those answers didn't work properly with my data.
Is there a function or a formula that I can use to remove duplicate strings within a single cell?
If,
A1=10,10,10,10,11,11,12,12,12 (the actual numbers are 13 digits each and they are either 2 or 3 unique numbers that repeat. I just need to capture each unique number)
Is there a simple way like RemoveDups() that will remove the duplicates and leave just . A1=10,11,12? Or do I need to create a UDF?
Function RemoveDuplicates(v As Variant) As String
Dim aSplit As Variant, aUnique() As Variant, vMatch As Variant, a As Variant
aSplit = Split(v, ",")
ReDim Preserve aUnique(0 To x)
aUnique(0) = Application.WorksheetFunction.Rept("|^|", 20)
For Each a In aSplit
vMatch = Application.Match(Trim(a), aUnique, 0)
If IsError(vMatch) Then
x = x + 1
ReDim Preserve aUnique(0 To x)
aUnique(x) = Trim(a)
End If
Next a
RemoveDuplicates = Join(Filter(aUnique, aUnique(0), False), ",")
End Function

Excel find remaining columns efficiently

I have a script (thanks to SO for the help with that one!) to allow a user to select a number of discontinuous columns and insert their indexes into an array. What I need to be able to do now is efficiently select the remaining columns i.e. the ones that the user didn't select into another array to perform a separate action on these columns.
For example, the user selects columns A,C,F,G and these indexes are put into the array Usr_col(). The remaining columns (B,D,E) need to be stored in the array rem_col()
All I can think of right now is to test every used column's index against the array of user-selected columns and, if it is not contained in that array, insert it into a new array. Something like this:
For i = 1 to ws.cells(1, columns.count).end(xltoright).column
if isinarray(i, Usr_col()) = false Then
rem_col(n) = i
n = n+1
end if
next
I am just looking for a more efficient solution to this.
I agree with #ScottHoltzman that this site wouldn't normally be the arena to make working code more efficient. However, this question puts a different slant on your previous one, as the most obvious solution would be to assign column numbers to one or other of your arrays in one loop.
The code below gives you a skeleton example. You'd need to check the user's selection for proper columns. Also, it isn't great form to redimension an array within the loop, but if the user selects adjacent columns then you'd need to acquire area count and column count to get the array size. I'll leave that to you if rediming within the loop jars with you:
Dim targetCols As Range, allCols As Range
Dim selColNum() As Long, unselColNum() As Long
Dim selIndex As Long, unselIndex As Long
Set targetCols = Application.InputBox("Select your columns", Type:=8)
For Each allCols In Sheet1.UsedRange.Columns
If Intersect(allCols, targetCols) Is Nothing Then
ReDim Preserve unselColNum(unselIndex)
unselColNum(unselIndex) = allCols.Column
unselIndex = unselIndex + 1
Else
ReDim Preserve selColNum(selIndex)
selColNum(selIndex) = allCols.Column
selIndex = selIndex + 1
End If
Next

dynamic LotusScript multi dimensional arrays

I was just doing some yicky code and I thought, instead of using three dynamic arrays, as such:
dim x() as string, y() as string, z() as string
It will be nicer to have a 3 dimensional dynamic array. But; the help and my fumbling experiments has not revealed the method of defining them.
This does not work:
dim x()() or dim(,2) or dim(,)
Any ideas anyone?
A dynamic array is declared the same way regardless of the number of dimensions (arrays in LotusScript can have up to 8 dimensions). According to your example I think it is a two dimensional array you want, where the first dimension is limited to three entries.
If you first declare the array as:
Dim x() As String
You can then specify bounds according to the following example:
Redim x( 0 To 2, 0 To 9 ) ' A two dimensional array
And if you need to enlarge the array later (and keep all the values) you can do it like this:
Redim Preserve x( 0 To 2, 0 To 99 )
Please keep in mind that only the bounds of last dimension can be changed once the number of dimensions of the array has been set.
You could use lists instead of arrays.
Dim x list as String
That is fully dynamic and takes a string as index. List can't contain lists, but lists can contain objects, so you might want to do
Public Class ListContainer
Public level2 List as String
End Class
This way you never need to REDIM preserve. A forall loops you savely through a list

Resources