I would like to loop through my table, store values into array LotN() (in the picture there were 2 individual sample data sets, to illustrate that I may encounter different number of unique lot numbers) (and the screen cap was an illustration only. Data were actually stored in an 2D array A1()).
candidate = "blah"
' loop through records, add to arrays (skip adding duplicated values with the function IsInArray = false)
For i = 2 To LR
If .Cells(i, 5).Value = candidate And IsInArray(.Cells(i, 2).Value, lotN) = False Then
q = q + 1
lotN(q) = .Cells(i, 2).Value
End If
Next i
Debug.Print "q = " & q ' try to know how many records were thrown into the arrays
ReDim Preserve lotN(1 To q)
Usually q will be equal to 1 to 3 for my data, but I have to prepare for q up to 6, for the procedures below. The next step I needed was to count the number of elements in another array A1() matching each of the elements in LotN().
' use counter to check the number of data pieces from another array A1() matching the elements within the array LotN()
For k = 1 To r
If A1(k, 2) = lotN(1) And lotN(1) <> "" Then
c = c + 1
End If
If A1(k, 2) = lotN(2) And lotN(2) <> "" Then
d = d + 1
End If
If A1(k, 2) = lotN(3) And lotN(3) <> "" Then ' with q = 2, the code stopped at this line with error "script out of range"
e = e + 1
End If
If A1(k, 2) = lotN(4) And lotN(4) <> "" Then
f = f + 1
End If
If A1(k, 2) = lotN(5) And lotN(5) <> "" Then
g = g + 1
End If
If A1(k, 2) = lotN(6) And lotN(6) <> "" Then
h = h + 1
End If
Next k
I want to create counters (c, d, e, f, g, h in the lines above) for each of the elements in the array. Since I am not sure how exactly q will be equal to, my attempt was to use lotN (position of element in this array) <> "" to allow increment of counters. That doesn't work, however. With q = 2, lines at or below the indicated will still cause an error "Script out of range".
How can I handle this error?
For this to work you will need the Microsoft Scripting Runtime library under tools-References.
This is the code commented:
Option Explicit
Const Candidate As String = "blah"
Sub Test()
'Here we will store the Candidates to enum
Dim Candidates As Dictionary: Set Candidates = LoadCandidates
'Another dictionary to hold the candidates on the array
Dim lotN As Dictionary: Set lotN = New Dictionary
For K = 1 To r
'If the value is in the Candidates Dictionary then
If Candidates.Exists(A1(K, 2)) Then
'If the Candidate is in the lotN already, add 1
If lotN.Exists(A1(K, 2)) Then
lotN(A1(K, 2)) = lotN(A1(K, 2)) + 1
'If not, add the candidate to the lotN and equal it to 1
Else
lotN.Add A1(K, 2), 1
End If
'output the number of times the candidate has appeared
A1(K, 7) = lotN(A1(K, 2))
End If
Next K
End Sub
Private Function LoadCandidates() As Dictionary
Set LoadCandidates = New Dictionary
For i = 2 To LR
If Cells(i, 5) = Candidate And Not LoadCandidates.Exists(Cells(i, 2).Value) Then
LoadCandidates.Add Cells(i, 2).Value, 1
End If
Next i
End
P.S.: Amend the code to fit your needs because you didn't post the whole code you need to reference the worksheet and workbook for the cells and give the A1 array...
Since the size of your array is variable, I advise you to instead of looping through a set range, to loop through the array itself.
counter = 0
For Each itm in lotN
counter = counter + 1
If A1(counter, 2) = itm Then
If counter = 1 Then
c = c + 1
ElseIf counter = 2 Then
d = d + 1
ElseIf counter = 3 Then
e = e + 1
ElseIf counter = 4 Then
f = f + 1
ElseIf counter = 5 Then
g = g + 1
ElseIf counter = 6 Then
h = h + 1
End If
End If
Next itm
Related
I'm creating an array from a text file and want to create a "subarray" from the main one.
The main array has the form
And I want to extract the A and B.
I create the "sub array" by splitting the strings from each row
For n = LBound(MainArray) To UBound(MainArray)
If Split(MainArray(n), " ")(0) = "Data" Then
ReDim SubArray(X)
SubArray(X) = Split(MainArray(n), " ")(1)
X = X + 1
End If
Next n
but doing this just returns the array (written as a vector now) (" ", B).
Why does A get overwritten by an empty space after the for loop finds the B?
Thanks and Happy Easter!
Note the example above is just a minimalist version of the real array.
This answer is predicated on Main array being a single dimension array.
The problem you are having is that you are nott creating new sub arrays each time tou get a new 'Data xxx" and consequently just keep overwriting the previous subarray.
You will be better served in you endeavour by using a dictionary of dictionaries.
To use dictionaries you either have to add a reference to the Microsoft Scripting Runtime or use 'CreateObject("Scripting.Dicitonary"). The first option is preferred when developing code or when you are a newbie because you get intellisense. You don't get intellisense when you use late bound objects (created by CreateObject).
Scripting.Dictionaries should be preferred over collections with keys because Dictionaries allow you to retreive the Keys or Items as arrays in their own right.
Here is your code modified to use scripting Dictionaries
Dim myD As Scripting.Dictionary
Set myD = New Scripting.Dictionary
Dim mySubDName As String
mySubDName = "Unknown"
Dim myItem As Variant
For Each myItem In MainArray
If InStr(myItem, "Data") > 0 Then
mySubDName = Trim(myItem)
If Not myD.exists(SubDName) Then
' Create a new sub dictionary with key 'Data XXXX'
myD.Add mySubDName, New Scripting.Dictionary
End If
Else
Dim myArray As Variant
myArray = Split(Trim(myItem), " ")
myD.Item(mySubDName).Add myArray(0), myArray(1)
End If
Next
Dictionary myD will have Keys of "Data A", Data B" etc.
You retrieve a sub dictionary using
'Where XXXX is A,B,C etc
set mySubD = myD.Item("Data XXXX")
The sub dictionary has the structure (using 00000007 700 as an example) of Key=00000007 and Item = 700
If you enumerate a Dictionary using for each it returns the Key as the control variable.
You can get an array of the Keys using the .Keys method
you can Get an array of the Items using the .Items Method
E.g.
myD.Keys gives the array ("Data A", "Data B", "Data C", ....."Data XXX"
myD.Item("Data B").Items will give the array ("0000005", "0000006",.....,"00000010, etc"
Please do take the ttime to read up on Scripting.Dictionaries as part of understanding the above.
Good luck with your coding.
Since you do not answer the clarification questions, please try the next code, which processes a 2D array, resulting two 2D arrays, corresponding to 'Data A' and 'Data B':
Sub Split2DArray()
Dim MainArray, arrA, arrB, n As Long, iA As Long, iB As Long, boolFirst As Boolean
'for exemplification place the picture content in A:A column, then place it in a (2D) array:
MainArray = Range("A1:A13").value
ReDim arrA(1 To 1, 1 To UBound(MainArray)): iA = 1
ReDim arrB(1 To 1, 1 To UBound(MainArray)): iB = 1
For n = LBound(MainArray) To UBound(MainArray)
If MainArray(n, 1) <> "" Then
If Split(MainArray(n, 1), " ")(0) = "Data" Then
If Not boolFirst Then
boolFirst = True
arrA(1, iA) = MainArray(n, 1): iA = iA + 1
Else
boolFirst = False
arrB(1, iB) = MainArray(n, 1): iB = iB + 1
End If
ElseIf boolFirst Then
arrA(1, iA) = MainArray(n, 1): iA = iA + 1
Else
arrB(1, iB) = MainArray(n, 1): iB = iB + 1
End If
End If
Next n
If iA > 1 Then ReDim Preserve arrA(1 To 1, 1 To iA - 1) 'only the second dimension can be preserved
If iB > 1 Then ReDim Preserve arrB(1 To 1, 1 To iB - 1)
Range("C1").Resize(UBound(arrA, 2), 1).value = Application.Transpose(arrA)
Range("D1").Resize(UBound(arrB, 2), 1).value = Application.Transpose(arrB)
End Sub
The code can be easily adapted to process 1D arrays. If this is the case I can show you how to proceed. If many such 'Data x' slices exist, you should use a Dictionary keeping each array.
The same processing way for 1D arrays. Using the same visual elocvent way of testing:
Sub Split1DArray()
Dim MainArray, arrA, arrB, n As Long, iA As Long, iB As Long, boolFirst As Boolean
'for exemplification place the picture content in A:A column, then place it in a (2D) array:
MainArray = Application.Transpose(Range("A1:A13").value) 'obtaining a 1D array from the same reange...
ReDim arrA(1 To UBound(MainArray)): iA = 1
ReDim arrB(1 To UBound(MainArray)): iB = 1
For n = LBound(MainArray) To UBound(MainArray)
If MainArray(n) <> "" Then
If Split(MainArray(n), " ")(0) = "Data" Then
If Not boolFirst Then
boolFirst = True
arrA(iA) = MainArray(n): iA = iA + 1
Else
boolFirst = False
arrB(iB) = MainArray(n): iB = iB + 1
End If
ElseIf boolFirst Then
arrA(iA) = MainArray(n): iA = iA + 1
Else
arrB(iB) = MainArray(n): iB = iB + 1
End If
End If
Next n
If iA > 1 Then ReDim Preserve arrA(1 To iA - 1) 'only the second dimension can be preserved
If iB > 1 Then ReDim Preserve arrB(1 To iB - 1)
Range("C1").Resize(UBound(arrA), 1).value = Application.Transpose(arrA)
Range("D1").Resize(UBound(arrB), 1).value = Application.Transpose(arrB)
End Sub
And a version using a dictionary, processing as many as `Data x' slices exist:
Sub Split1DArrayDict()
Dim MainArray, n As Long, x As Long, arrIt, dict As Object
'for exemplification place the picture content in A:A column, then place it in a (2D) array:
MainArray = Application.Transpose(Range("A1:A18").value) 'obtaining a 1D array from the same range...
Set dict = CreateObject("Scripting.Dictionary")
For n = LBound(MainArray) To UBound(MainArray)
If MainArray(n) <> "" Then
If Split(MainArray(n), " ")(0) = "Data" Then
x = x + 1
dict.Add x, Array(MainArray(n))
arrIt = dict(x)
Else
ReDim Preserve arrIt(UBound(arrIt) + 1)
arrIt(UBound(arrIt)) = MainArray(n)
dict(x) = arrIt
End If
End If
Next n
For n = 0 To dict.count - 1
cells(1, 3 + n).Resize(UBound(dict.items()(n)) + 1, 1).value = Application.Transpose(dict.items()(n))
Next n
End Sub
I have the below snippit for excel 2013 VBA
For Each r In rr
If Not r.Range.Height = 0 Then
FNum = FNum + 1
ReDim Preserve testArr(1 To FNum, 1 To 23)
testArr(FNum) = r
End If
Next r
My goal is to get all the visible rows from a filtered table into an array.
The table can be any number of rows, but always 23 columns.
I found that the height will be zero if it is hidden. But for the life of me, I cannot figure out how to get the entire row into the array.
r = listrow
rr = listrows
YES, I know a looping redim sucks.
SpecialCells(xlCellTypeVisible)
doesnt work either because it stops at the first hidden row/column.
I may just dump the entire table into the array and then filter the array. I havent figured out how to pull the active filter from the table to apply it, but I havent looked deeply into that yet. Thats what I will be doing now, because I am stuck for the other way.
Any and all advice is welcome.
DM
To avoid REDIM or double loops you can use something like Application.WorksheetFunction.Subtotal(3, Range("A2:A500000")) to quickly count the number of visible rows.
See this question
I define my Target range using .SpecialCells(xlCellTypeVisible). Target.Cells.Count / Target.Columns.Count will give you the row count. Finally I iterate over the cells in the Target range incrementing my counters based off of the Target.Columns.Count.
Public Sub FilteredArray()
Dim Data As Variant, r As Range, Target As Range
Dim rowCount As Long, x As Long, y As Long
Set Target = WorkSheets("Sheet1").ListObjects("Table1").DataBodyRange.SpecialCells(xlCellTypeVisible)
If Not Target Is Nothing Then
rowCount = Target.Cells.Count / Target.Columns.Count
ReDim Data(1 To rowCount, 1 To Target.Columns.Count)
x = 1
For Each r In Target
y = y + 1
If y > Target.Columns.Count Then
x = x + 1
y = 1
End If
Data(x, y) = r.Value
Next
End If
End Sub
The code below will create an array for all the rows and store each of these into another array that will store all info in sheet:
Function RowsToArray()
Dim lastRow: lastRow = ActiveWorkbook.ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row
Dim lastCol: lastCol = ActiveWorkbook.ActiveSheet.Cells(1, Columns.Count).End(xlToLeft).Column
Dim newArr()
ReDim newArr(lastRow)
For r = 0 To lastRow - 1
Dim rowarr()
ReDim rowarr(lastCol)
For c = 0 To lastCol - 1
rowarr(c) = Cells(r + 1, c + 1).Value
Next c
newArr(r) = rowarr
Next r
End Function
Can you loop over the cells in rr rather than the rows? If so, as #SJR says, you can only Redim Preserve the final dimension, so we're going to have to switch your dimensions. You can then use r.EntireRow.Hidden to check if we're in a visible row and increase the bound of your array by one if we are.
The following assumes that your data starts in column A:
For Each r In rr
If Not r.EntireRow.Hidden Then
If r.Column = 1 Then
If UBound(testArr, 2) = 0 Then
ReDim testArr(1 To 23, 1 To 1)
Else
ReDim Preserve testArr(1 To 23, 1 To UBound(testArr, 2) + 1)
End If
End If
testArr(r.Column, UBound(testArr, 2)) = r
End If
Next r
Edit:
Alternatively, you can keep using ListRows, but loop through twice, once to set the bounds of your array, and once to fill the array (which will have its own internal loop to run through the row...):
For Each r In rr
If Not r.Range.Height = 0 Then
Fnum = Fnum + 1
ReDim testArr(1 To Fnum, 1 To 3)
End If
Next r
Fnum = 0
For Each r In rr
If Not r.Range.RowHeight = 0 Then
Fnum = Fnum + 1
dumarray = r.Range
For i = 1 To 3
testArr(Fnum, i) = dumarray(1, i)
Next i
End If
Next r
Thanks all, a combo of answers led me to: (not very elegant, but quick)
For Each r In rr
If Not r.Range.Height = 0 Then
TNum = TNum + 1
End If
Next r
ReDim testArr(TNum, 23)
For Each r In rr
If Not r.Range.Height = 0 Then
FNum = FNum + 1
For i = 1 To 23
testArr(FNum, i) = r.Range.Cells(, i)
Next i
End If
Next r
I am putting data in my array I created in VBA.
I wrote some formulas in the macro but when I paste them it is not working.
Sub Button3_Click()
Application.Calculation = xlManual
'update list of document
'declare variables
Dim i As Long
Dim m As Long
Dim n As Long
Dim j As Long
Dim lNumColumn As Long
Dim XLsheetD As String
Dim range_data As String
Dim tab_data()
Dim Data As ListObject
Dim track_list As ListObject
'ini Data
Set Data = Sheets("track_list").ListObjects("sheets_list")
Set track_list = Sheets("track_list").ListObjects("track_list")
Application.Goto Reference:=track_list
Column = ActiveCell.Column
Row = ActiveCell.Row - 1
range_data = "A9:A6000"
'import list
m = Data.ListRows.Count
nb_docs_prev = 0
n = 0
lNumColumn = Application.CountA(Sheets("track_list").Range("B6:Z6"))
For k = 1 To lNumColumn
If Range("B6").Offset(0, k - 1) = "manual" Then
GoTo nextcol
End If
n = 0
For i = 1 To m
XLsheetD = Data.DataBodyRange(i, 1)
lNumCases = Application.CountA(Sheets(XLsheetD).Range(range_data))
nb_docs = lNumCases - 1
c = Data.DataBodyRange(i, k + 1)
If c = "-" Then
n = n + lNumCases
GoTo nextsheet
End If
If k = 1 Then
ReDim Preserve tab_data(lNumColumn, nb_docs + nb_docs_prev + 1)
End If
For j = 0 To nb_docs
If Range("B6").Offset(0, k - 1) = "hyperlink" Then
tab_data(k - 1, n) = ""
Else
tab_data(k - 1, n) = Sheets(XLsheetD).Range("A9").Offset(j, c - 1)
End If
n = n + 1
Next j
nb_docs_prev = nb_docs + nb_docs_prev + 1
nextsheet:
Next i
nextcol:
Next k
'Put data in order
lNumCases = track_list.ListRows.Count
'==>test if data already in the table
For p = 1 To n
For q = 1 To lNumCases
If track_list.DataBodyRange(q, 1) = tab_data(0, p - 1) Then
For r = 1 To lNumColumn
If Range("B6").Offset(0, r - 1) = "manual" Or Range("B6").Offset(0, r - 1) = "semi-automatic" Then
If tab_data(r - 1, p - 1) <> "" Then
Else
tab_data(r - 1, p - 1) = track_list.DataBodyRange(q, r).Formula
End If
End If
Next r
End If
Next q
Next p
' formulas for new lines
For p = 1 To n
tab_data(5 - 1, p - 1) = "=IF([#[DCN no]]<>"""",INDEX(DCN!R9C3:R229C3,MATCH([#[DCN no]],DCN!R9C1:R229C1,0)),"""")"
tab_data(11 - 1, p - 1) = "=IF([#[DCN no]]<>"""",IF(INDEX(DCN!R9C7:R229C7,MATCH([#[DCN no]],DCN!R9C1:R229C1,0))<>"""",""CLOSED"",""OPEN""),"""")"
Next p
'paste list
Application.Goto Reference:=track_list
Selection.ClearContents
track_list.Resize Range(Cells(Row, Column), Cells(Row + n, Column + track_list.ListColumns.Count - 1))
Application.Goto Reference:=track_list
Selection = Application.Transpose(tab_data())
Application.Calculation = xlAutomatic
End Sub
Do you know why ?
Before doing that my macro was working. It is just those formulas impossible to paste.
Thanks
Your statement
Range("S8:AY250") = Application.Transpose(tab_data())
Can only be used to write the values of tab_data to the worksheet
You need to explicitly write your array formula to the worksheet via the method Bruce Wayne identified.
Range("S8").formulaArray = "=IF([#[DCNno]]<>"""",INDEX(DCN!R9C3:R229C3,MATCH([#[DCNno]],DCN!R9C1:R229C1,0)),"""")"
Will get you closer to where you want to be, but the above cell reference is undoubtedly wrong, and I can't determine which cell you actually need, since you're using variables in your array elements
I am trying to have my code prompt the user to select a range of data of 3 width and variable length. There will only be 30 values those with some rows being blank. I want to have these 30 values populate into 30 text boxes in a userform of mine (this is so values don't have to be manually entered). I looked around and figured my route should be Application.Inputbox and then pass it into an array were the blank rows can be weeded out with for loops. I don't know how to pass the user selected table into a 2D array though.
Sub selectRange()
Dim r(1 To 14, 1 To 3) As Variant, ran As Range, calB(1 To 30) As Long, i As Integer, j As Integer, k As Integer, l As Integer
dozerCal.Hide
Set r = Application.InputBox("Select the Cal B table.", Type:=8)
For j = 1 To 14
For i = 1 To 3
If Abs(r(j, i)) > 0 Then
calB(l) = r(j, i)
l = l + 1
End If
Next
Next
lx = calB(1)
ly = calB(2)
lz = calB(3)
rx = calB(4)
ry = calB(5)
rz = calB(6)
ix = calB(7)
iy = calB(8)
iz = calB(9)
sx = calB(10)
sy = calB(11)
sz = calB(12)
p1x = calB(13)
p1y = calB(14)
p1z = calB(15)
p2x = calB(16)
p2y = calB(17)
p2z = calB(18)
lfx = calB(19)
lfy = calB(20)
lfz = calB(21)
lrx = calB(22)
lry = calB(23)
lrz = calB(24)
rfx = calB(25)
rfy = calB(26)
rfz = calB(27)
rrx = calB(28)
rry = calB(29)
rrz = calB(30)
ActiveWorkbook.Close
dozercall.Show
End Sub
Thanks in advance for everyone's help.
Edit: I missed that you were using the input box wrong, however I will leave this answer as it presents a way to collapse a variable range of user input from a multidimensional array into a single dimension array.
This should get you started. Basically it will read the user's input, dynamically create a one-dimensional array of the correct size (rows * columns), and read all the values in the range the user selects to this one dimensional array. It will then loop through the one dimensional array and print the values back out to the window.
I think this is what you're looking for, but if you need further clarification I can add some. I added comments so you can see what each section is doing.
Option Explicit
Private Sub TestArrays()
Dim calBTemp() As Variant, calB() As Variant
Dim i As Long, j As Long, x As Long
Dim rngInput As Range
Set rngInput = Application.InputBox("Select the Cal B table.", "Select Range", Type:=8)
'Read the user input, check for empty input
'If empty input, exit the subroutine
If Not rngInput Is Nothing Then
calBTemp = rngInput
Else
Exit Sub
End If
'Create the one-dimensional array dynamically based on user selection
ReDim calB((UBound(calBTemp, 1) - LBound(calBTemp, 1) + 1) * (UBound(calBTemp, 2) - LBound(calBTemp, 2) + 1))
'Loop through our multidimensional array
For i = LBound(calBTemp, 1) To UBound(calBTemp, 1)
For j = LBound(calBTemp, 2) To UBound(calBTemp, 2)
'Assign the value to our one dimensional array
calB(x) = calBTemp(i, j)
x = x + 1
Next j
Next i
'Loop through our one dimensional array
For i = LBound(calB) To UBound(calB)
Debug.Print calB(i)
Next i
End Sub
So I just wasn't using the Application.Inputbox right. If you return it as a range it will configure to the proper sized 2D array it seams and you can call/manipulate data from there. Here is a working sub.
Sub selectRange()
Dim ran As Range, calB(1 To 30) As Double, i As Integer, j As Integer, k As Integer, l As Integer
dozerCal.Hide
Set ran = Application.InputBox("Select the Cal B table.", Type:=8)
l = 1
For j = 1 To 14
For i = 1 To 3
If Abs(ran(j, i)) > 0 Then
calB(l) = ran(j, i)
l = l + 1
End If
Next
Next
lx = calB(1)
ly = calB(2)
lz = calB(3)
rx = calB(4)
ry = calB(5)
rz = calB(6)
ix = calB(7)
iy = calB(8)
iz = calB(9)
sx = calB(10)
sy = calB(11)
sz = calB(12)
p1x = calB(13)
p1y = calB(14)
p1z = calB(15)
p2x = calB(16)
p2y = calB(17)
p2z = calB(18)
lfx = calB(19)
lfy = calB(20)
lfz = calB(21)
lrx = calB(22)
lry = calB(23)
lrz = calB(24)
rfx = calB(25)
rfy = calB(26)
rfz = calB(27)
rrx = calB(28)
rry = calB(29)
rrz = calB(30)
ActiveWorkbook.Close
dozerCal.Show
End Sub
This code will do the trick (and forces the user to select 3 columns and 14 rows):
Sub selectRange()
Dim selectedRange As Range
Dim errorMessage As String
errorMessage = vbNullString
Dim ran As Range, calB(1 To 30) As Long, i As Integer, j As Integer, k As Integer, l As Integer
Do
'doesn't handle cancel event
Set selectedRange = Application.InputBox("Select the Cal B table.", _
Type:=8, Title:="Please select 14 rows and 3 columns" & errorMessage)
errorMessage = "; previous selection was invalid"
Loop While selectedRange.Columns.Count <> 3 Or selectedRange.Rows.Count <> 14
For j = 1 To 14
For i = 1 To 3
If Abs(selectedRange.Cells(j, i)) > 0 Then
calB(l) = selectedRange.Cells(j, i)
l = l + 1
End If
Next
Next
...rest of your code
So, I'm trying to print modified iterations of an array of 100; for the first row I want 1 to 100 of the array, for the second 2 to 100, all the way to the 100th row with just array(100), and all of these rows starting with column A. I can print the first row just fine, but for the subsequent ones I'm not getting any output.
q = 1
For m = 1 To last_age
Sheets("Sheet1").Range(Cells(q, 1), Cells(q, UBound(Data) + 1)) = Data 'Works the first pass, but not for q>1
For p = 0 To UBound(Data) - 1
Data(p) = Data(p + 1)
Next p
If UBound(Data) > 0 Then
ReDim Data(0 To UBound(Data) - 1)
q = q + 1
End If
Next m
All my variables seem to be incrementing correctly, but after the first m loop my Data array isn't being put in the second row. Any thoughts?
Slightly different approach:
Sub Tester()
Dim data(100), i, last_age, sht As Worksheet, q, m
'fill test array
For i = 1 To 100: data(i - 1) = i: Next
Set sht = Sheets("Sheet1")
last_age = 100
q = 1
sht.Cells(q, 1).Resize(1, UBound(data) + 1) = data
For m = 2 To last_age
q = q + 1
sht.Cells(1, 1).Offset(0, m - 1).Resize( _
1, (UBound(data) + 1) - (m - 1)).Copy _
sht.Cells(q, 1)
Next m
End Sub
You are re-dimensioning your array in this line:
ReDim Data(0 To UBound(Data) - 1)
but you are not using the Preserve keyword so your data is getting deleted. Try using:
ReDim Preserve Data(0 To UBound(Data) - 1)