Why we can't assign to static parametrized array VBA? - vba

Why we can't assign values from range into static array :
Sub test()
'error occours
Dim a(1 to 10) as Double
'also don't work :
'Dim a(1 To 10, t To 1) as Double
a = Range("A1:A10")
End Sub

Because the array has already been allocated, regardless of how many dimensions you use.
Dim x(1 to 10, 1 to 1) As Variant '// You've allocated the array
x = Range("A1:A10").Value '// Can't allocate to an already allocated array
You can declare an array of type Variant without allocating it and use that instead:
Dim x() As Variant '// Array is NOT allocated
x = Range("A1:A10") '// x = Array sized 1 to 10, 1 to 1
Assigning a range directly to an array in this way will always return a type Variant/Variant and so the receiving array must be of type Variant also.
You could create a UDF to do this for you, but it kind of defies the point of assigning directly from range:
Sub SO()
Dim a As Variant
a = RangeToArray(Range("A1:A10"))
End Sub
Function RangeToArray(rng As Range) As Variant
ReDim x(1 To rng.Rows.count, 1 To rng.Columns.count) As Variant
Dim r As Long, c As Long
For r = 1 To rng.Rows.count
For c = 1 To rng.Columns.count
x(r, c) = rng.Cells(r, c)
Next c
Next r
RangeToArray = x
End Function

Related

How to get range of cells into a specific array dimension

I need to get a range of cells into an array, which by itself is simple enough:
Dim matchArray As Variant
matchArray = Sheets(lookupSheet).Range("B2:B12000").Value2
This creates a two-dimensional array with one column as the second dimension and if you expand the range to include a second column it creates a two-dimensional array with two columns for the second dimension:
matchArray = Sheets(lookupSheet).Range("B2:C12000").Value2
But what if the two columns aren't next to each other and you don't want the one in the middle?
matchArray = Sheets(lookupSheet).Range("B2:B12000,D2:D12000").Value2
The above would be my best guess but it doesn't work, it only returns the first range specified.
So what I need is a way to return a range cell values into a specific dimension of the array.
I know I could do it by looping through the rows but that would take far too long with the number of rows I'm going to be working with.
You do need a loop -- but loop over VBA arrays rather than individual cells:
Sub Test()
Dim A As Variant, B As Variant, C As Variant
Dim i As Long
B = Sheets(lookupSheet).Range("B2:B12000").Value2
C = Sheets(lookupSheet).Range("D2:D12000").Value2
ReDim A(1 To 11999, 1 To 2)
For i = 1 To 11999
A(i, 1) = B(i, 1)
A(i, 2) = C(i, 2)
Next i
'do stuff with A
End Sub
This should only take a fraction of a second.
You can do it with a ragged array:
Dim var1(1 To 2) As Variant
Dim var As Variant
var = Range("A1:A10").Value2
var1(1) = var
var = Range("c1:c10").Value2
var1(2) = var
MsgBox var1(1)(3, 1)
Here are a couple more ways:
Sub Example1()
Const lookupSheet As String = "Sheet1"
Dim matchArray As Variant, arr1 As Variant, arr2 As Variant
With Sheets(lookupSheet)
arr1 = WorksheetFunction.Transpose(.Range("B2:B12000").Value2)
arr2 = WorksheetFunction.Transpose(.Range("D2:D12000").Value2)
matchArray = WorksheetFunction.Transpose(Array(arr1, arr2))
End With
End Sub
Sub Example2()
Const lookupSheet As String = "Sheet1"
Dim matchArray As Variant
Dim x As Long
With Sheets(lookupSheet)
matchArray = .Range("B2:B12000").Resize(, 2).Value2
For Each v In .Range("D2:D12000").Value2
x = x + 1
matchArray(x, 2) = v
Next
End With
End Sub
Probably no quicker than John Coleman's answer, but I think this does what you want.
Sub x()
Dim matchArray, r As Range
Set r = Sheets(lookupSheet).Range("B2:D12000")
matchArray = Application.Index(r, Evaluate("Row(1:" & r.Rows.Count & ")"), Array(1, 3))
End Sub

How do i dim values in an array as arrays?

just out of curiosity.
is it possible to dim values in an array as their own individual array?
Sub test()
Dim ar(5) As Variant
ar(1) = a
ar(2) = b
ar(3) = c
ar(4) = d
ar(5) = e
For i = 1 To UBound(ar)
Dim ar(i) As Variant '<---doesn't work :(
Next i
End Sub
If you're after a matrix style array, then you could just define a multi-dimensional array:
Dim ar(5, x) As Variant
But it seems as though you want a jagged array, ie an array of arrays. In that case you just assign an Array() Variant to each element of your array:
Dim ar(5) As Variant
ar(0) = Array(1, 2, 3)
And the syntax to access the 'sub-elements' would be ar(x)(y):
Debug.Print ar(0)(1)
You should be able to set one (or more) position of a Variant array to be an array:
Sub test()
Dim ar(5) As Variant
Dim ar1(1 To 4) As Variant
ar1(1) = 5
ar1(2) = "x"
Set ar1(3) = ActiveSheet
ar1(4) = 10
ar(1) = "a"
ar(2) = "b"
ar(3) = ar1
ar(4) = "d"
ar(5) = "e"
Debug.Print ar(1)
Debug.Print ar(3)(1)
Debug.Print ar(3)(3).Name
End Sub

Why am I having issues assigning an array to a Range

Why is the the first item of my array getting assigned to all cells in the range?
Private Sub sample()
Dim arr() As Double, rng As Range, i As Double
ReDim arr(1 To 100)
For i = 1 To 100
arr(i) = i * Rnd
Next i
Set rng = Range("A1:A100")
rng.Value = arr
End Sub
Based on the Locals window, my array has populated as expected:
But when the array is assigned to the the range, it assigns the first value to all cells:
In order to assign the array to a range, the array needs to be declared as a 2 dimensional array. Even if the 2nd dimension only has 1 element:
ReDim arr(1 To 100, 1 To 1)
The working example looks like this:
Private Sub sample()
Dim arr() As Double, rng As Range, i As Double
ReDim arr(1 To 100, 1 To 1)
For i = 1 To 100
arr(i, 1) = i * Rnd
Next i
Set rng = Range("A1:A100")
rng.Value = arr
End Sub
The array is a horizontal 1 dimensional array and it needs to be transposed to a vertical 1 dimensional array:
Private Sub sample()
Dim arr() As Double, rng As Range, i As Double
ReDim arr(1 To 100)
For i = 1 To 100
arr(i) = i * Rnd
Next i
Set rng = Range("A1:A100")
rng.Value = Application.Transpose(arr)
End Sub
The only caveat of this is if there is more than roughly 64,500 elements then the transposing needs to be done manually, with a loop.
Try this:
Sub sample()
Dim arr() As Double, rng As Range, i As Double
ReDim arr(1 To 100)
Set rng = Range("A1:A100")
For i = 1 To 100
arr(i) = i * Rnd
rng.Cells(i, 1).Value = arr(i)
Next i
End Sub

type mismatch assigning range to 1d array

I've got a range in a text format containing values and numbers. I am trying to assign the numbers only to an array and then I will assign the text values to another array without having to loop through the range. However, this code says - type mismatch?
Sub Igra()
Dim Arr() As Variant
'convert the range values from text to general
Sheets("Sheet1").Range("R32:W32").NumberFormat = "General"
Sheets("Sheet1").Range("R32:W32").Value = Sheets("Sheet1").Range("R32:W32").Value
' assign only the numbers to the array
Arr = Sheets("Sheet1").Range("R32:W32").SpecialCells(xlCellTypeConstants, xlNumbers).Value
End Sub
This should work then
Dim Arr() As Variant
Sheets("Sheet1").Range("R32:W32").SpecialCells(xlCellTypeConstants, xlNumbers).Copy
Sheets("Sheet1").Range("A1").PasteSpecial xlValues
Arr = Range(Range("A1"), Range("A1").End(xlToRight))
Dim R As Long
Dim C As Long
For R = 1 To UBound(Arr, 1) ' First array dimension is rows.
For C = 1 To UBound(Arr, 2) ' Second array dimension is columns.
MsgBox Arr(R, C)
Next C
Next R
Try this
Sub Sample()
Dim ws As Worksheet
Dim Arr() As Variant
Dim rng As Range, cl As Range
Dim n As Long, i As Long
Set ws = ThisWorkbook.Sheets("Sheet1")
Set rng = ws.Range("R32:W32")
n = Application.WorksheetFunction.Count(rng)
If n = 0 Then Exit Sub
ReDim Arr(1 To n)
i = 1
For Each cl In rng
If IsNumeric(cl.Value) Then
Arr(i) = cl.Value
i = i + 1
End If
Next cl
'~~> Only for demonstration purpose
For i = 1 To n
Debug.Print Arr(i)
Next i
End Sub

Array to Excel Range

I'm new to VBA and trying to write an array to an excel range through an array UDF.
I'm trying to output the array to a maximum number of rows that the formula was placed in. I am using the Microsoft Scripting Library for the dictionary, if that matters.
With an array formula in excel (CTRL+Shift+Enter), how do I resize my array to the range that the formula was placed in and then place the array in the cells?
I would like the formula on the cells to be =test("G1:J20") and the formula will be placed in the cells A1:B20.
Code:
Function test(ByVal inputRange As Range) As Variant
Dim Cell As Variant
Dim D As Dictionary
Dim Arr() As Variant
Dim i As Long
Set D = New Dictionary
' Remove duplicates
For Each Cell In inputRange
If D.Exists(CStr(Cell.Value)) = False Then
D.Add CStr(Cell.Value), 1
Else
D.Exists (Cell.Value)
D.Item(Cell.Value) = D.Item(Cell.Value) + 1
End If
Next
D.Remove vbNullString
Redim Arr(0 To Application.Max(D.Count, Application.Caller.Cells.Count))
'Fill the array with the keys from the Dictionary
For i = 0 To D.Count - 1
Arr(i) = D.Keys(i)
Next i
test = Application.Transpose(Arr)
End Function
To read and write arrays to cells you need a 2D array. For example:
Dim data() as Variant, N as Long, M as Long
' Say you want a 100×50 array
N = 100 : M = 50
ReDim data(1 to N, 1 to M)
' Fill data()
Range("A1").Resize(N,M).Value = data
Or to just read values
Dim data() as Variant, N as Long, M as Long, i as Long, j as Long
data = Range("A1:AX100").Value
N = UBOUND(data,1) : M = UBOUND(data,2)
For i = 1 to N
For j = 1 to M
Debug.Print(data(i,j))
Next j
Next i
Edit 1 I got rid of the evil Integer types and replaced them with Long, the native 32-bit integers in VBA.
Here is a method to put an array into a worksheet range, is this what you meant?
Sub test()
Dim v(0 To 2, 0 To 2) As Variant
Dim r As Range
'fill the array with values
populate v
'range must be same dimensions as array, in this case 3x3
Set r = ActiveSheet.Range("A1:C3")
'this simply puts array into range values
r.Value2 = v
End Sub
Function populate(v As Variant)
For i = 0 To 2
For j = 0 To 2
v(j, i) = i * j * j - i + 2
Next j
Next i
End Function
However, since you're already looping through the dictionary for the values, why not just write the values directly to the worksheet? You can mimic the transpose by swapping your row and column indices
Sub test()
Dim dict As Dictionary
Set dict = New Dictionary
'fill dictionary with values
populate dict
'loop through dictionary, and add items to worksheet
For i = 0 To dict.Count - 1
ActiveSheet.Cells(1, i + 1).Value = dict.Keys(i)
ActiveSheet.Cells(2, i + 1).Value = dict.Items(i)
Next i
End Sub
Function populate(dict As Dictionary)
dict.Add "help", "me"
dict.Add "I'm", "lost"
dict.Add "everything", "1"
dict.Add "or", "0"
End Function