I have a for next loop that runs through a couple hundred thousand lines making changes on most. Could an array to make this code run faster?
The example of my for loop. Sometimes it gets overloaded and crashes Excel. (FYI my loop has to run bottom to top for it to do its intended purpose.)
Sub RemoveDuplicates()
Dim shWorkBook As Worksheet
Dim wkb As Workbook
Dim FullYearData As Worksheet
Set wkb = ThisWorkbook
With wkb
Set shWorkBook = .Sheets("Workbook")
Set shFullYearData = .Sheets("FullYearData")
End With
Dim i As Long
Dim LastRowW As Long
On Error Resume Next
Call TurnOffCalc
FirstRowW = shWorkBook.Cells(1, 1).Row
FirstColW = shWorkBook.Cells(1, 1).Column
LastRowW = shWorkBook.Cells(Rows.Count, 1).End(xlUp).Row
LastColW = shWorkBook.Cells(2, Columns.Count).End(xlToLeft).Column
i = LastRowW
Sum = 0
shWorkBook.Activate
For i = LastRowW To 1 Step -1
If shWorkBook.Cells(i, 7) = shWorkBook.Cells(i - 1, 7) Then
shWorkBook.Cells(i, 26) = vbNullString
End If
If shWorkBook.Cells(i, 26).Value <> "" Then
shWorkBook.Cells(i, 27) = Sum + Cells(i, 25).Value
Sum = 0
ElseIf shWorkBook.Cells(i, 26).Value = "" Then
Sum = shWorkBook.Cells(i, 25).Value + Sum
End If
Next
p = FirstRowW + 1
For p = FirstRowW + 1 To LastRowW Step 1
shWorkBook.Cells(p, 28) = Application.WeekNum(shWorkBook.Cells(p, 3))
Next
shWorkBook.Cells(1, 28).Value = "Week Number"
Call TurnOnCalc
End Sub
Try something like this:
Sub RemoveDuplicates()
Dim shWorkBook As Worksheet
Dim wkb As Workbook
Dim FullYearData As Worksheet
Dim i As Long, Sum
Dim LastRowW As Long, LastColW As Long, tbl As Range, data
Set wkb = ThisWorkbook
With wkb
Set shWorkBook = .Sheets("Workbook")
'Set shFullYearData = .Sheets("FullYearData")
End With
LastRowW = shWorkBook.Cells(Rows.Count, 1).End(xlUp).Row
LastColW = shWorkBook.Cells(2, Columns.Count).End(xlToLeft).Column
Set tbl = shWorkBook.Range("A1").Resize(LastRowW, 28) 'include "Week number" (?)
data = tbl.Value 'get the range value as an array
data(1, 28) = "Week Number"
Sum = 0
For i = LastRowW To 1 Step -1
If data(i, 7) = data(i - 1, 7) Then data(i, 26) = vbNullString
If data(i, 26).Value <> "" Then
data(i, 27) = Sum + data(i, 25).Value
Sum = 0
Else
Sum = data(i, 25).Value + Sum
End If
If i > 1 Then data(i, 28) = CLng(Format(data(i, 3), "ww"))
Next
tbl.Value = data 'return the data
End Sub
Related
I have an array loading column references from column C.
The user will enter the current month, e.g. March, then the array should load February column value "U" and January value "L", then the rest of my code will run.
How do I setup the array to stop after the value "L" is found?
Sub CopyData() 'with array
Dim wb1 As Workbook
Dim wkshtname As String
Dim colArray(1 To 5) As Variant
Dim i As Range, rng As Range
Dim lrow As Long, colcounter As Long, y As Long, retcol As Long, z As Long
Dim StartHere As String, x As String, col As String
Dim cell
Dim sht As Worksheet
Set wb1 = ThisWorkbook
wkshtname = "Retro-" & wb1.Sheets("Instructions").Range("B4").Value
StartHere = wb1.Sheets("Instructions").Range("B4")
lrow = wb1.Sheets("Member Prem.Pymts").Cells(Rows.Count, 1).End(xlUp).Row
If StartHere = "January" Then
MsgBox "No Retro Commissions to be posted", vbOKOnly
Exit Sub
End If
'delete sheet if it exists
For Each sht In wb1.Worksheets
If sht.Name = wkshtname Then
Application.DisplayAlerts = False
wb1.Sheets(wkshtname).Delete
Application.DisplayAlerts = True
End If
Next sht
With wb1
.Sheets.Add(After:=.Sheets(.Sheets.Count)).Name = wkshtname
With .Sheets(wkshtname)
.Cells(1).Resize(1, 8).Value = Array("ID", "Last Name", "First Name", "Premium", "Commission Amt", "month for", "agent", "sheet row")
End With
'returns Paid in Month 30-150 day columns
col = Application.WorksheetFunction.Match(StartHere, wb1.Sheets("Lookups").Range("$A$1:$A$13"), 0)
z = 1
For retcol = 1 To 5
colArray(retcol) = wb1.Sheets("Lookups").Cells(col - z, 3)
z = z + 1
Next retcol
With .Sheets("Member Prem.Pymts") 'reference target sheet
y = 1
For colcounter = LBound(colArray, 1) To UBound(colArray, 1)
x = 4 'starting row number data is found on
For Each i In .Range(colArray(colcounter) & "4:" & colArray(colcounter) & lrow) 'loop through Member Prem.Payments column cells
If i.Value = StartHere Then
wb1.Sheets(wkshtname).Cells(Rows.Count, "A").End(xlUp).Offset(1, 0) = .Range("A" & x)
wb1.Sheets(wkshtname).Cells(Rows.Count, "B").End(xlUp).Offset(1, 0) = .Range("B" & x)
wb1.Sheets(wkshtname).Cells(Rows.Count, "C").End(xlUp).Offset(1, 0) = .Range("C" & x)
wb1.Sheets(wkshtname).Cells(Rows.Count, "D").End(xlUp).Offset(1, 0) = .Range("BR" & x)
wb1.Sheets(wkshtname).Cells(Rows.Count, "E").End(xlUp).Offset(1, 0) = wb1.Sheets("Commissions to Pay").Range(wb1.Sheets("Lookups").Cells(col - y, 4) & x)
wb1.Sheets(wkshtname).Cells(Rows.Count, "F").End(xlUp).Offset(1, 0) = .Range(colArray(colcounter) & "2")
wb1.Sheets(wkshtname).Cells(Rows.Count, "G").End(xlUp).Offset(1, 0) = .Range("DR" & x)
wb1.Sheets(wkshtname).Cells(Rows.Count, "H").End(xlUp).Offset(1, 0) = x
End If
x = x + 1
Next
y = y + 1
Next colcounter
End With
End Sub
This is what is stored in the array when I run the code.
I'm trying to load the array and then the array needs to stop loading after the value is "L".
The array will never have more than 5 elements.
EDIT: Stripped down to the core problem for testing
Sub CopyData()
Dim rngMonths As Range, c As Range, wb1
Dim colArray(), StartHere, col, retcol As Long
Set wb1 = ActiveWorkbook
Set rngMonths = wb1.Sheets("Lookups").Range("A2:A13") 'month lookup range
StartHere = "March" 'for testing
col = Application.Match(StartHere, rngMonths, 0)
If Not IsError(col) Then
Set c = rngMonths.Cells(col)
ReDim colArray(1 To 5) '<<<<<<<<<<<<
For retcol = 1 To 5
colArray(retcol) = c.Offset(0, 2).Value 'col C value
If colArray(retcol) = "L" Then Exit For 'exit if Col C="L"
Set c = c.Offset(-1) 'next cell up
Next retcol
ReDim Preserve colArray(1 To retcol) '<<<<<resize array
Debug.Print Join(colArray, ",")
Else
MsgBox "No month match!", vbExclamation
Exit Sub
End If
End Sub
I'm trying to have a for loop that takes my weeks and then another for loop that looks at my product to calculate the sales for this year, last year and then the difference. I am getting 0's for all of the weeks except for the current week, any idea what is wrong with my code? Thanks
Sub Weekly_Recap()
Dim h, d As Worksheet
Dim myarray(), answers() As Variant
'Dim week, datarange As Range
Dim D1, i As Long
Set h = Worksheets("Helper")
Set d = Worksheets("Data")
myarray = d.Range("P2:P51")
D1 = UBound(myarray, 1)
ReDim answers(1 To D1, 1 To 3)
For i = 1 To D1
If myarray(i, 1) <= h.Range("A1") Then
For j = 1 To 17
answers(i, 1) = Application.WorksheetFunction.SumIfs(d.Range("G:G"), d.Range("B:B"), myarray(i, 1), d.Range("F:F"), h.Cells(j, 4))
answers(i, 2) = Application.WorksheetFunction.SumIfs(d.Range("H:H"), d.Range("B:B"), myarray(i, 1), d.Range("F:F"), h.Cells(j, 4))
answers(i, 3) = (answers(i, 1) - answers(1, 2)) / answers(i, 2)
If h.Cells(j, 4) = "FLAVORED/FUNCTIONAL WATER" Then
h.Range(h.Range("F2"), h.Range("F2").Offset(D1, 2)).Value = answers
ElseIf h.Cells(j, 4) = "SALTY BAGGED/CANISTER SNACKS" Then
h.Range(h.Range("K2"), h.Range("K2").Offset(D1, 2)).Value = answers
End If
Next j
End If
Next i
End Sub
Kinda hard to understand what you are trying to do. When I tried to run your code in debug mode I noticed that line with offset is overwriting data in previous lines, and that is where you are getting all 0's. In lets say loop i = 1 and j = 1 you get some value, but in i = 1 and j = 2 you don't (sumif returns 0) and then you overwrite it in variable answers and then paste it in worksheet, at the end only last one has not been overwritten.
You need swap the loops to calculate all the weeks for each product in turn otherwise the figure for week1/product1 will be overwritten by week1/product2 then week1/product3 etc.
Option Explicit
Sub Sales()
Dim arWeeks, NoOfWeeks As Long, iLastWeek As Long
Dim rngSales1 As Range, rngSales2 As Range
Dim rngWeek As Range, rngProduct As Range
Dim iWeek As Long, sProduct As String
Dim h As Worksheet, d As Worksheet
Dim j As Long, i As Long
Set h = Worksheets("Helper")
Set d = Worksheets("Data")
Set rngSales1 = d.Range("G:G")
Set rngSales2 = d.Range("H:H")
Set rngWeek = d.Range("B:B")
Set rngProduct = d.Range("F:F")
arWeeks = d.Range("P2:P51")
iLastWeek = h.Range("A1").Value
NoOfWeeks = UBound(arWeeks)
ReDim answers(1 To NoOfWeeks, 1 To 3) 'yr1,yr2,diff
For j = 1 To 17 ' products
sProduct = h.Cells(j, 4)
For i = 1 To NoOfWeeks ' weeks
iWeek = arWeeks(i, 1)
If iWeek <= iLastWeek Then
With Application.WorksheetFunction
answers(i, 1) = .SumIfs(rngSales1, rngWeek, iWeek, rngProduct, sProduct)
answers(i, 2) = .SumIfs(rngSales2, rngWeek, iWeek, rngProduct, sProduct)
End With
If answers(i, 2) <> 0 Then
answers(i, 3) = (answers(i, 1) - answers(1, 2)) / answers(i, 2)
End If
End If
Next i
If sProduct = "FLAVORED/FUNCTIONAL WATER" Then
h.Range("F2").Resize(NoOfWeeks, 3).Value = answers
ElseIf sProduct = "SALTY BAGGED/CANISTER SNACKS" Then
h.Range("k2").Resize(NoOfWeeks, 3).Value = answers
End If
Next j
MsgBox "Done ", vbInformation
End Sub
My goal is to select a column of about 300,000 cells and round each cell's value to two decimal places.
I found that looping an array is far faster than looping through cells.
It is much faster if I have the whole array post its data into the cells after the loop rather than during because again posting any data in a loop takes too much time.
Is there a way to write all the values from the new array ("varArray") after the loop is completed?
Sub RoundedTwoDecimalPlaces()
Dim i As Integer
Dim MyArray() As Variant ' Declare dynamic array.
Dim LastRow As Integer
Dim lStart As Double
Dim lEnd As Double
lStart = Timer
LastRow = Cells(1, Selection.Column).End(xlDown).Row
MyArray = Range("a1:a8").Value2
ReDim MyArray(LastRow) ' Resize to x amount of elements.
For i = 1 To LastRow
MyArray(i) = Round(Cells(i, Selection.Column), 2) ' Initialize array.
Next i
''this is where I can't get my array to post into the cells dynamically.
Selection.Value = MyArray()
''to see the amount of time it takes to finish.
'' My goal is to do 300,000 lines quickly
lEnd = Timer
Debug.Print "Duration = " & (lEnd - lStart) & " seconds"
End Sub
You can get the array directly from the range and then restore the altered values:
Sub RoundedTwoDecimalPlaces()
Dim i As Integer
Dim arr As Variant
Dim lStart As Double
Dim ws As Worksheet, col as Long
Set ws = ActiveSheet
col = Selection.Column
lStart = Timer
With ws.Range(ws.Cells(1, col), ws.Cells(1, col).End(xlDown))
arr = .Value
For i = 1 to Ubound(arr, 1)
arr(i, 1) = Round(arr(i, 1), 2)
Next i
.Value = arr
end with
Debug.Print "Duration = " & (Timer - lStart) & " seconds"
End Sub
Here is how I did it using #Tim Williams Code.
I had to loop it because the array has a max character limit.
Here is the finished code:
Sub loopthrough()
Dim i As Integer
Dim arr As Variant
Dim arr1 As Variant
Dim arr2 As Variant
Dim lStart As Double
Dim ws As Worksheet, col As Long
LastRow = Cells(1, Selection.Column).End(xlDown).Row
Set ws = ActiveSheet
col = Selection.Column
lStart = Timer
If LastRow < 30001 Then
With ws.Range(ws.Cells(1, col), ws.Cells(1, col).End(xlDown))
arr = .Value2
For i = 1 To UBound(arr, 1)
If IsNumeric(arr(i, 1)) Then
arr(i, 1) = Round(arr(i, 1), 2)
Else
arr(i, 1) = arr(i, 1)
End If
Next i
.Value2 = arr
End With
Else ''if selection is more than 30,000 lines.
n = 1
Z = 30000
Do While Z < LastRow
With ws.Range(ws.Cells(n, col), ws.Cells(Z, col))
arr = .Value2
For i = 1 To UBound(arr, 1)
If IsNumeric(arr(i, 1)) Then
arr(i, 1) = Round(arr(i, 1), 2)
Else
arr(i, 1) = arr(i, 1)
End If
Next i
.Value2 = arr
End With
n = n + 30000
Z = Z + 30000
Loop
With ws.Range(ws.Cells(n, col), ws.Cells(n, col).End(xlDown))
arr = .Value2
For i = 1 To UBound(arr, 1)
If IsNumeric(arr(i, 1)) Then
arr(i, 1) = Round(arr(i, 1), 2)
Else
arr(i, 1) = arr(i, 1)
End If
Next i
.Value2 = arr
End With
End If
Debug.Print "Duration = " & (Timer - lStart) & " seconds"
End Sub
I am trying to work through a code that utilizes a system to check two different worksheets by using a for loop and highlight the differences/edits made in the second sheet ("Version 2") onto the first sheet ("Original"). I have a feeling that I need to utilize an array but I'm not advanced enough where I know how to store the values and then later write them onto another sheet (down below).
I've gotten the code so that it highlights all the relevant cells, but now I'm trying to output it into a report (on another sheet called 'Logged Changes') which will summarize all the cell addresses where edits were made. Please forgive all the variables as this is from an old code set where variables are not explicitly defined:
Private Sub CompareBasic()
Dim actSheet As Range
Dim k As Integer
Dim o As Long
Dim p As Long
Dim i As Integer
Dim change As Integer
o = Worksheets("Original").Cells(2, Columns.Count).End(xlToLeft).Column
p = Worksheets("Original").Range("A" & Rows.Count).End(xlUp).Row
change = 0
Sheets("Original").Select
For i = 2 To p
For k = 1 To o
If IsNumeric(Worksheets("Original").Cells(i, k).Value) = True Then
If Worksheets("Original").Cells(i, k).Value <> Worksheets("Version 2").Cells(i, k).Value Then
Worksheets("Original").Cells(i, k).Interior.ColorIndex = 37
change = change + 1
End If
Else
If StrComp(Worksheets("Original").Cells(i, k), Worksheets("Version 2").Cells(i, k), vbBinaryCompare) <> 0 Then
Worksheets("Original").Cells(i, k).Interior.ColorIndex = 37
change = change + 1
End If
End If
Next k
Next i
Unload Me
MsgBox "Number of cells edited counted: " & change, vbOKOnly + vbExclamation, "Summary"
b = Empty
answer = MsgBox("Do you want to run the Report?", vbYesNo + vbQuestion)
If answer = vbYes Then
If Sheet_Exists("Logged Changes") = False Then
Sheet_Name = "Logged Changes"
Worksheets.Add(After:=Sheets(Sheets.Count)).Name = Sheet_Name
End If
Worksheets("Logged Changes").Range("A1") = "Edited Requirements"
Else
Unload Me
End If
End Sub
I have tried fiddling around with the code, but didn't want to clog it up with any unnecessary/broken lines. Any help would be greatly appreciated!
Try this:
Option Explicit
Private Sub CompareBasic()
Const SHT_REPORT As String = "Logged Changes"
Dim actSheet As Range
Dim c As Integer
Dim o As Long
Dim p As Long
Dim r As Long
Dim change As Long, wsOrig As Worksheet, wsNew As Worksheet, wsReport As Worksheet
Dim dataOrig, dataNew, rngData As Range, v1, v2, bDiff As Boolean
Dim arrUpdates
Set wsOrig = Worksheets("Original")
Set wsNew = Worksheets("Version 2")
o = wsOrig.Cells(2, Columns.Count).End(xlToLeft).Column
p = wsOrig.Range("A" & Rows.Count).End(xlUp).Row
Set rngData = wsOrig.Range("A2", wsOrig.Cells(p, o))
dataOrig = rngData.Value 'get an array of data
dataNew = wsNew.Range(rngData.Address).Value 'array of new data
ReDim arrUpdates(1 To rngData.Cells.Count, 1 To 3) 'for change info
change = 0
For r = 1 To UBound(dataOrig, 1)
For c = 1 To UBound(dataOrig, 2)
v1 = dataOrig(r, c)
v2 = dataNew(r, c)
If Len(v1) > 0 Or Len(v2) > 0 Then
If IsNumeric(v1) Then
bDiff = v1 <> v2
Else
bDiff = StrComp(v1, v2, vbBinaryCompare) <> 0
End If
End If
'any difference?
If bDiff Then
change = change + 1
With rngData.Cells(r, c)
arrUpdates(change, 1) = .Address
.Interior.ColorIndex = 37
End With
arrUpdates(change, 2) = v1
arrUpdates(change, 3) = v2
End If
Next c
Next r
If MsgBox("Do you want to run the Report?", vbYesNo + vbQuestion) = vbYes Then
With GetSheet(SHT_REPORT, ThisWorkbook)
.UsedRange.ClearContents
.Range("A1") = "Edited Requirements"
.Range("A3").Resize(1, 3).Value = Array("Address", wsOrig.Name, wsNew.Name)
.Range("A4").Resize(change, 3).Value = arrUpdates
End With
Else
'Unload Me
End If
End Sub
'return as sheet from wb by name (and create it if it doesn't exist)
Function GetSheet(wsName, wb As Workbook) As Worksheet
Dim rv As Worksheet
On Error Resume Next
Set rv = wb.Worksheets(wsName)
On Error GoTo 0
If rv Is Nothing Then
Set rv = wb.Worksheets.Add(After:=wb.Worksheets(wb.Worksheets.Count))
rv.Name = "Logged Changes"
End If
Set GetSheet = rv
End Function
Sheet Differences
Option Explicit
Sub logChanges()
Const ws1Name As String = "Original"
Const ws2Name As String = "Version 2"
Const wsResult As String = "Logged Changes"
Const FirstRow As Long = 2
Const FirstColumn As Long = 1
Const LastRowColumn As Long = 1
Const LastColumnRow As Long = 2
Const ResultFirstCell As String = "A2"
Dim Headers As Variant
Headers = Array("Id", "Address", "Original", "Version 2")
Dim wb As Workbook: Set wb = ThisWorkbook
Dim ws As Worksheet: Set ws = wb.Worksheets(ws1Name)
Dim LastRow As Long
LastRow = ws.Cells(ws.Rows.Count, LastRowColumn).End(xlUp).Row
Dim LastColumn As Long
LastColumn = ws.Cells(LastColumnRow, ws.Columns.Count) _
.End(xlToLeft).Column
Dim rng As Range
Set rng = ws.Range(ws.Cells(FirstRow, FirstColumn), _
ws.Cells(LastRow, LastColumn))
Dim Data1 As Variant: Data1 = rng.Value
Set ws = wb.Worksheets(ws2Name)
Dim Data2 As Variant: Data2 = ws.Range(rng.Address).Value
Dim Result() As Variant
Dim i As Long, j As Long, k As Long
For i = 1 To UBound(Data1)
For j = 1 To UBound(Data1, 2)
If Data1(i, j) <> Data2(i, j) Then GoSub writeResult
Next j
Next i
If k > 0 Then
transpose2D Result
On Error GoTo MissingResultSheet
Set ws = wb.Worksheets(wsResult)
On Error GoTo 0
ws.Range(ws.Range(ResultFirstCell), _
ws.Cells(ws.Rows.Count, ws.Columns.Count)).Clear
ws.Range(ResultFirstCell).Resize(k, UBound(Result, 2)).Value = Result
MsgBox "Found '" & k & "' difference(s) in range '" _
& rng.Address(False, False) & "'.", vbInformation
Else
MsgBox "Found no differences in range '" _
& rng.Address(False, False) & "'.", vbExclamation
End If
Exit Sub
writeResult:
k = k + 1
ReDim Preserve Result(1 To 4, 1 To k)
Result(1, k) = k
Result(2, k) = getAddress(i + FirstRow - 1, j + FirstColumn - 1)
Result(3, k) = Data1(i, j)
Result(4, k) = Data2(i, j)
Return
MissingResultSheet:
If Err.Number = 9 Then
wb.Worksheets.Add After:=wb.Sheets(wb.Sheets.Count)
With ActiveSheet
.Name = wsResult
If .Range(ResultFirstCell).Row > 1 Then
.Range(ResultFirstCell).Offset(-1) _
.Resize(, UBound(Headers) + 1).Value = Headers
End If
End With
Resume ' i.e. the code continues with Set ws = wb.Worksheets(wsResult)
Else
'?
Exit Sub
End If
End Sub
Function getAddress(aRow As Long, aColumn As Long) As String
getAddress = ActiveSheet.Cells(aRow, aColumn).Address(False, False)
End Function
Sub transpose2D(ByRef Data As Variant)
Dim i As Long, j As Long
Dim Result As Variant
ReDim Result(LBound(Data, 2) To UBound(Data, 2), _
LBound(Data) To UBound(Data))
For i = LBound(Data) To UBound(Data)
For j = LBound(Data, 2) To UBound(Data, 2)
Result(j, i) = Data(i, j)
Next j
Next i
Data = Result
End Sub
This solution for converting a column number to a string without using objects Function to convert column number to letter? could be used to write a descent getAddress function.
I would like to take data sets from Sheet 1 and fill in table values in Sheet 2. I believe using a multidimensional array to be the optimum way of accomplishing this.
Sheet 1 is setup as such:
Column A = "Dates", Column C = "SNs", Column E = "M0s", and Column F = "HNs".
An operator enters in an M0 value, and if a ("E").Row has that value, I want that row's SN, HN, and Date to be entered into Sheet 2. Just because two rows have the same M0 doesn't mean they have the same SN, HN, or Date. I would like each row's values to be stored separately, hence a multidimensional array (3 dimensional in this case).
The code below is my successful attempt at storing all SNs in an single dimensional array (based on M0 entered) and then entering those values into Sheet 2.
Sub FillSheet2()
Dim varSNarray As Variant
Dim M0cell As Range
Dim SNcell As Long 'could be substituted with Variant or String
ReDim varSNarray(0)
For Each M0cell In ws.Range("E7:E200000").Cells
If M0cell.Value <> vbNullString Then
If M0cell.Value = varPrintM0 Then
SNcell = ws.Range("C" & M0cell.Row).Value
varSNarray(UBound(varSNarray)) = SNcell
ReDim Preserve varSNarray(UBound(varSNarray) + 1) As Variant
End If
End If
Next M0cell
ReDim Preserve varSNarray(UBound(varSNarray) - 1)
Dim i As Long
For i = LBound(varSNarray) To UBound(varSNarray)
Dim ws2range As Range
Dim ws2SNcellnum As Long
If i > 149 Then
Set ws2range = ws2.Range("AN6:AN55")
ws2SNcellnum = i - 144
ws2.Range("AN" & ws2SNcellnum).Value = varSNarray(i)
ElseIf i > 99 Then
Set ws2range = ws2.Range("AA6:AA55")
ws2SNcellnum = i - 94
ws2.Range("AA" & ws2SNcellnum).Value = varSNarray(i)
ElseIf i > 49 Then
Set ws2range = ws2.Range("N6:N55")
ws2SNcellnum = i - 44
ws2.Range("N" & ws2SNcellnum).Value = varSNarray(i)
Else
Set ws2range = ws2.Range("A6:A55")
ws2SNcellnum = i + 6
ws2.Range("A" & ws2SNcellnum).Value = varSNarray(i)
End If
Next i
End Sub
I would like to add HN and Date along with SN as this sub runs. I don't know how to augment the array to allow for HN and Date storage though. Below is how I imagine it would look like. However, I cannot successfully create my array. I'm fairly sure it has something to do with my variable setups.
Dim varSNarray As Variant
Dim M0cell As Range
Dim SNcell As Long
Dim HNcell As Long
Dim Datecell As Long
ReDim varSNarray(0, 0, 0)
For Each M0cell In ws.Range("E7:E200000").Cells
If M0cell.Value <> vbNullString Then
If M0cell.Value = varPrintM0 Then
SNcell = ws.Range("C" & M0cell.Row).Value
varSNarray(UBound(varSNarray), HNcell, Datecell) = SNcell
varSNarray(SNcell, UBound(varSNarray), Datecell) = HNcell 'Script out of range error
varSNarray(SNcell, HNcell, UBound(varSNarray)) = Datecell
ReDim Preserve varSNarray(UBound(varSNarray) + 1, UBound(varSNarray) + 1, UBound(varSNarray) + 1) As Variant
End If
End If
Next M0cell
ReDim Preserve varSNarray(UBound(varSNarray) - 1)
Dim i As Long
For i = LBound(varSNarray) To UBound(varSNarray)
Dim ws2range As Range
Dim ws2SNcellnum As Long
If i > 149 Then
Set ws2range = ws2.Range("AN6:AN55")
ws2SNcellnum = i - 144
ws2.Range("AN" & ws2SNcellnum).Value = varSNarray(i)
ws2.Range("AN" & ws2SNcellnum).Value = varSNarray(HNcell)
ws2.Range("AN" & ws2SNcellnum).Value = varSNarray(Datecell)
''''
Removed this section has its the same as above
''''
Set ws2range = ws2.Range("A6:A55")
ws2SNcellnum = i + 6
ws2.Range("A" & ws2SNcellnum).Value = varSNarray(i)
ws2.Range("A" & ws2SNcellnum).Value = varSNarray(HNcell)
ws2.Range("A" & ws2SNcellnum).Value = varSNarray(Datecell)
End If
Next i
How do I store data into a 3 dimensional array and then successful pull 1 dimension from the array at a time?
I don't think an array is necessary here, just write the records to Sheet 2 as they are found. For example
Option Explicit
Sub FillSheet2()
Const COL_DATE = "A"
Const COL_SN = "C"
Const COL_M0 = "E"
Const COL_HN = "F"
Const START_ROW = 7
' target sheet
Const TARGET_START_ROW = 5
Const TARGET_START_COL = 1 'A
Const COL_REPEAT = 13 ' N, AA, AN
Const MAX_ROWS = 50
Dim wb As Workbook, wsSource As Worksheet, wsTarget As Worksheet
Set wb = ThisWorkbook
Set wsSource = wb.Sheets("Sheet1")
Set wsTarget = wb.Sheets("Sheet2")
wsTarget.Cells.Clear
Dim iRow As Integer, iLastRow As Integer, iCount As Integer
Dim iTargetRow As Integer, iTargetCol As Integer, sM0 As String
Dim varPrintM0 As String
iTargetCol = TARGET_START_COL
iTargetRow = TARGET_START_ROW
varPrintM0 = "Test4"
iCount = 0
iLastRow = wsSource.Range(COL_M0 & Rows.Count).End(xlUp).Row
' ----------
With wsSource
For iRow = START_ROW To iLastRow
sM0 = .Range(COL_M0 & iRow)
If sM0 = varPrintM0 Then
With wsTarget.Cells(iTargetRow, iTargetCol)
.Offset(0, 0) = wsSource.Range(COL_SN & iRow).Value
.Offset(0, 1) = wsSource.Range(COL_HN & iRow).Value
.Offset(0, 2) = wsSource.Range(COL_DATE & iRow).Value
End With
iTargetRow = iTargetRow + 1
If iTargetRow >= MAX_ROWS + TARGET_START_ROW Then
iTargetCol = iTargetCol + COL_REPEAT
iTargetRow = TARGET_START_ROW
End If
iCount = iCount + 1
End If
Next
End With
MsgBox iCount & " rows copied", vbInformation, "Finished"
' --------
End Sub
If you do want to use an array replace the code between the ------ lines above with this
Dim ar(5, 50, 3) As Variant ' max of 5 blocks of 50 records
Dim t As Integer, r As Long
t = 1: r = 1
' fill array
With wsSource
For iRow = START_ROW To iLastRow
sM0 = .Range(COL_M0 & iRow)
If sM0 = varPrintM0 Then
With wsTarget.Cells(iTargetRow, iTargetCol)
ar(t, r, 0) = sM0
ar(t, r, 1) = wsSource.Range(COL_SN & iRow).Value
ar(t, r, 2) = wsSource.Range(COL_HN & iRow).Value
ar(t, r, 3) = wsSource.Range(COL_DATE & iRow).Value
End With
r = r + 1
If r > MAX_ROWS Then
r = 1
t = t + 1
End If
iCount = iCount + 1
End If
Next
End With
' output array
Dim iLastTable As Long, c As Long
iLastTable = t
For t = 1 To iLastTable
For r = 1 To 50
c = 1 + COL_REPEAT * (t - 1)
With wsTarget.Cells(r + 4, c)
.Offset(0, 0) = ar(t, r, 1)
.Offset(0, 1) = ar(t, r, 2)
.Offset(0, 2) = ar(t, r, 3)
End With
Next r
Next t
MsgBox iCount & " rows copied using Array", vbInformation, "Finished"