Please can you help me to make my macro shorter using a loop.
This is the coefficient trend line applied to my dynamic array at B2:G - xlend.
Sub TESTONE()
'||||||||||||||||||||||||||||||||||||||||||||||||| LINE B |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Range("I3").Formula = "=FORECAST(18,B3:B19,$A$3:$A$19)"
Range("I4").Formula = "=TREND(B3:B19)"
Range("I5").Formula = "=INTERCEPT(B3:B19,$A$3:$A$19)"
Range("I6").Formula = "=INDEX(LINEST(B3:B19,LN($A$3:$A$19)),1,2)"
Range("I7").Formula = "=EXP(INDEX(LINEST(LN(B3:B19),LN($A$3:$A$19),,),1,2))"
Range("I8").Formula = "=EXP(INDEX(LINEST(LN(B3:B19),$A$3:$A$19),1,2))"
Range("I9").Formula = "=INDEX(LINEST(B3:B19,$A$3:$A$19^{1,2}),1,3)"
Range("I10").Formula = "=INDEX(LINEST(B3:B19,$A$3:$A$19^{1,2,3}),1,4)"
'||||||||||||||||||||||||||||||||||||||||||||||||| LINE C |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Range("J3").Formula = "=FORECAST(18,C3:C19,$A$3:$A$19)"
Range("J4").Formula = "=TREND(C3:C19)"
Range("J5").Formula = "=INTERCEPT(C3:C19,$A$3:$A$19)"
Range("J6").Formula = "=INDEX(LINEST(C3:C19,LN($A$3:$A$19)),1,2)"
Range("J7").Formula = "=EXP(INDEX(LINEST(LN(C3:C19),LN($A$3:$A$19),,),1,2))"
Range("J8").Formula = "=EXP(INDEX(LINEST(LN(C3:C19),$A$3:$A$19),1,2))"
Range("J9").Formula = "=INDEX(LINEST(C3:C19,$A$3:$A$19^{1,2}),1,3)"
Range("J10").Formula = "=INDEX(LINEST(C3:C19,$A$3:$A$19^{1,2,3}),1,4)"
'||||||||||||||||||||||||||||||||||||||||||||||||| LINE D |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Range("K3").Formula = "=FORECAST(18,D3:D19,$A$3:$A$19)"
Range("K4").Formula = "=TREND(D3:D19)"
Range("K5").Formula = "=INTERCEPT(D3:D19,$A$3:$A$19)"
Range("K6").Formula = "=INDEX(LINEST(D3:D19,LN($A$3:$A$19)),1,2)"
Range("K7").Formula = "=EXP(INDEX(LINEST(LN(D3:D19),LN($A$3:$A$19),,),1,2))"
Range("K8").Formula = "=EXP(INDEX(LINEST(LN(D3:D19),$A$3:$A$19),1,2))"
Range("K9").Formula = "=INDEX(LINEST(D3:D19,$A$3:$A$19^{1,2}),1,3)"
Range("K10").Formula = "=INDEX(LINEST(D3:D19,$A$3:$A$19^{1,2,3}),1,4)"
'||||||||||||||||||||||||||||||||||||||||||||||||| LINE E |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Range("L3").Formula = "=FORECAST(18,E3:E19,$A$3:$A$19)"
Range("L4").Formula = "=TREND(E3:E19)"
Range("L5").Formula = "=INTERCEPT(E3:E19,$A$3:$A$19)"
Range("L6").Formula = "=INDEX(LINEST(E3:E19,LN($A$3:$A$19)),1,2)"
Range("L7").Formula = "=EXP(INDEX(LINEST(LN(E3:E19),LN($A$3:$A$19),,),1,2))"
Range("L8").Formula = "=EXP(INDEX(LINEST(LN(E3:E19),$A$3:$A$19),1,2))"
Range("L9").Formula = "=INDEX(LINEST(E3:E19,$A$3:$A$19^{1,2}),1,3)"
Range("L10").Formula = "=INDEX(LINEST(E3:E19,$A$3:$A$19^{1,2,3}),1,4)"
'||||||||||||||||||||||||||||||||||||||||||||||||| LINE F |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Range("M3").Formula = "=FORECAST(18,F3:F19,$A$3:$A$19)"
Range("M4").Formula = "=TREND(F3:F19)"
Range("M5").Formula = "=INTERCEPT(F3:F19,$A$3:$A$19)"
Range("M6").Formula = "=INDEX(LINEST(F3:F19,LN($A$3:$A$19)),1,2)"
Range("M7").Formula = "=EXP(INDEX(LINEST(LN(F3:F19),LN($A$3:$A$19),,),1,2))"
Range("M8").Formula = "=EXP(INDEX(LINEST(LN(F3:F19),$A$3:$A$19),1,2))"
Range("M9").Formula = "=INDEX(LINEST(F3:F19,$A$3:$A$19^{1,2}),1,3)"
Range("M10").Formula = "=INDEX(LINEST(F3:F19,$A$3:$A$19^{1,2,3}),1,4)"
'||||||||||||||||||||||||||||||||||||||||||||||||| LINE G |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Range("N3").Formula = "=FORECAST(18,G3:G19,$A$3:$A$19)"
Range("N4").Formula = "=TREND(G3:G19)"
Range("N5").Formula = "=INTERCEPT(G3:G19,$A$3:$A$19)"
Range("N6").Formula = "=INDEX(LINEST(G3:G19,LN($A$3:$A$19)),1,2)"
Range("N7").Formula = "=EXP(INDEX(LINEST(LN(G3:G19),LN($A$3:$A$19),,),1,2))"
Range("N8").Formula = "=EXP(INDEX(LINEST(LN(G3:G19),$A$3:$A$19),1,2))"
Range("N9").Formula = "=INDEX(LINEST(G3:G19,$A$3:$A$19^{1,2}),1,3)"
Range("N10").Formula = "=INDEX(LINEST(G3:G19,$A$3:$A$19^{1,2,3}),1,4)"
End Sub
Write Formulas in a Loop
Option Explicit
Sub WriteFormulas()
Const fRow As Long = 3
Const lrCol As String = "A"
Const Cols As String = "I:N"
With ActiveSheet
Dim lRow As Long: lRow = .Cells(.Rows.Count, lrCol).End(xlUp).Row
If lRow < fRow Then Exit Sub
Dim Formulas() As String: Formulas = GetFormulas(fRow, lRow)
Dim rrg As Range: Set rrg = .Columns(Cols).Rows(fRow)
Dim n As Long
For n = LBound(Formulas) To UBound(Formulas)
rrg.Formula = Formulas(n)
Set rrg = rrg.Offset(1)
Next n
End With
End Sub
Function GetFormulas( _
ByVal fRow As Long, _
ByVal lRow As Long) _
As Variant
Dim Formulas() As String: ReDim Formulas(1 To 8)
Formulas(1) = "=FORECAST(18,B" & fRow & ":B" & lRow & ",$A$" _
& fRow & ":$A$" & lRow & ")"
Formulas(2) = "=TREND(B" & fRow & ":B" & lRow & ")"
Formulas(3) = "=INTERCEPT(B" & fRow & ":B" & lRow & ",$A$" _
& fRow & ":$A$" & lRow & ")"
Formulas(4) = "=INDEX(LINEST(B" & fRow & ":B" & lRow & ",LN($A$" _
& fRow & ":$A$" & lRow & ")),1,2)"
Formulas(5) = "=EXP(INDEX(LINEST(LN(B" & fRow & ":B" & lRow _
& "),LN($A$" & fRow & ":$A$" & lRow & "),,),1,2))"
Formulas(6) = "=EXP(INDEX(LINEST(LN(B" & fRow & ":B" & lRow _
& "),$A$" & fRow & ":$A$" & lRow & "),1,2))"
Formulas(7) = "=INDEX(LINEST(B" & fRow & ":B" & lRow & ",$A$" _
& fRow & ":$A$" & lRow & "^{1,2}),1,3)"
Formulas(8) = "=INDEX(LINEST(B" & fRow & ":B" & lRow & ",$A$" _
& fRow & ":$A$" & lRow & "^{1,2,3}),1,4)"
GetFormulas = Formulas
End Function
Try this:
Private Sub TestOne()
For j = 66 To 71
For i = 73 To 78
Range(Chr(i) & "3").Formula = "=FORECAST(18," & Chr(j) & "3:" & Chr(j) & "19,$A$3:$A$19)"
Range(Chr(i) & "4").Formula = "=TREND(" & Chr(j) & "3:" & Chr(j) & "19)"
Range(Chr(i) & "5").Formula = "=INTERCEPT(" & Chr(j) & "3:" & Chr(j) & "19,$A$3:$A$19)"
Range(Chr(i) & "6").Formula = "=INDEX(LINEST(" & Chr(j) & "3:" & Chr(j) & "19,LN($A$3:$A$19)),1,2)"
Range(Chr(i) & "7").Formula = "=EXP(INDEX(LINEST(LN(" & Chr(j) & "3:" & Chr(j) & "19),LN($A$3:$A$19),,),1,2))"
Range(Chr(i) & "8").Formula = "=EXP(INDEX(LINEST(LN(" & Chr(j) & "3:" & Chr(j) & "19),$A$3:$A$19),1,2))"
Range(Chr(i) & "9").Formula = "=INDEX(LINEST(" & Chr(j) & "3:" & Chr(j) & "19,$A$3:$A$19^{1,2}),1,3)"
Range(Chr(i) & "10").Formula = "=INDEX(LINEST(" & Chr(j) & "3:" & Chr(j) & "19,$A$3:$A$19^{1,2,3}),1,4)"
Next
Next End Sub
You could try this one, I created variables like countFormulaColumns and strReferenceRangeAddress simply for readability, they are not 100% necessary if this is just a one-time task.
Sub TESTONE()
' Starting from column I, there are 6 consecutive columns having similar formula generated in VBA
Dim countFormulaColumns As Long: countFormulaColumns = 6
' Starting from B3:B19, ends at G3:G19, this string variable represtents all reference addresses in the formula
Dim strReferenceRangeAddress As String
Dim colOffset As Long
For colOffset = 0 To countFormulaColumns - 1
strReferenceRangeAddress = Range("B3:B19").Offset(0, colOffset).Address(False, False)
With Range("I3")
.Offset(0, colOffset).Formula = "=FORECAST(18," & strReferenceRangeAddress & ",$A$3:$A$19)"
.Offset(1, colOffset).Formula = "=TREND(" & strReferenceRangeAddress & ")"
.Offset(2, colOffset).Formula = "=INTERCEPT(" & strReferenceRangeAddress & ",$A$3:$A$19)"
.Offset(3, colOffset).Formula = "=INDEX(LINEST(" & strReferenceRangeAddress & ",LN($A$3:$A$19)),1,2)"
.Offset(4, colOffset).Formula = "=EXP(INDEX(LINEST(LN(" & strReferenceRangeAddress & "),LN($A$3:$A$19),,),1,2))"
.Offset(5, colOffset).Formula = "=EXP(INDEX(LINEST(LN(" & strReferenceRangeAddress & "),$A$3:$A$19),1,2))"
.Offset(6, colOffset).Formula = "=INDEX(LINEST(" & strReferenceRangeAddress & ",$A$3:$A$19^{1,2}),1,3)"
.Offset(7, colOffset).Formula = "=INDEX(LINEST(" & strReferenceRangeAddress & ",$A$3:$A$19^{1,2,3}),1,4)"
End With
Next colOffset
End Sub
Here is one implementation of what #BigBen has suggested in his comment above.
With Range("L3:L10")
.Cells(1).Formula = "=FORECAST(18,E3:E19,$A$3:$A$19)"
.Cells(2).Formula = "=TREND(E3:E19)"
.Cells(3).Formula = "=INTERCEPT(E3:E19,$A$3:$A$19)"
.Cells(4).Formula = "=INDEX(LINEST(E3:E19,LN($A$3:$A$19)),1,2)"
.Cells(5).Formula = "=EXP(INDEX(LINEST(LN(E3:E19),LN($A$3:$A$19),,),1,2))"
.Cells(6).Formula = "=EXP(INDEX(LINEST(LN(E3:E19),$A$3:$A$19),1,2))"
.Cells(7).Formula = "=INDEX(LINEST(E3:E19,$A$3:$A$19^{1,2}),1,3)"
.Cells(8).Formula = "=INDEX(LINEST(E3:E19,$A$3:$A$19^{1,2,3}),1,4)"
.Copy Destination:=.Resize(, 3)
End With
For "smart" formula replication, the way to output an array to a range is handy. Specifically, when you output a one-column vertical array of formulas into a two-dimensional range, Excel automatically shifts the column references
Sub TESTONE()
Range("I3:N10").Formula = WorksheetFunction.Transpose(Array( _
"=FORECAST(18,B3:B19,$A$3:$A$19)", _
"=TREND(B3:B19)", _
"=INTERCEPT(B3:B19,$A$3:$A$19)", _
"=INDEX(LINEST(B3:B19,LN($A$3:$A$19)),1,2)", _
"=EXP(INDEX(LINEST(LN(B3:B19),LN($A$3:$A$19),,),1,2))", _
"=EXP(INDEX(LINEST(LN(B3:B19),$A$3:$A$19),1,2))", _
"=INDEX(LINEST(B3:B19,$A$3:$A$19^{1,2}),1,3)", _
"=INDEX(LINEST(B3:B19,$A$3:$A$19^{1,2,3}),1,4)"))
End Sub
A clear example with one-column vertical array of formulas:
Sub FormulasFromArray()
Range("A1:D4") = WorksheetFunction.Transpose(Array("=A10", "=A10", "=A10", "=A10"))
End Sub
The same happens with a horizontal array, but the references to the rows are shifted
Sub FormulasFromArrayHorizontal()
Range("A1:D4") = Array("=A10", "=A10", "=A10", "=A10")
End Sub
I have a data entry form that let's users enter the data into specific cells. What i want is a way to track changes to the cell values. When the data entered initially through the entry form, i don't want that information to be tracked. However, if the user tries to change/edit the data that was entered then i want to add a comment to show the initial value and the amended one as well.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim singlecell As Range
If Target.Cells.CountLarge > 1000 Then Exit Sub
For Each singlecell In Target
If singlecell.Comment Is Nothing Then
singlecell.AddComment Now & " - " & singlecell.Value & " - " & Environ("UserName")
Else
singlecell.Comment.Text _
vbNewLine & Now & " - " & singlecell.Value & " - " & Environ("UserName") _
, Len(singlecell.Comment.Text) + 1 _
, False
End If
singlecell.Comment.Shape.TextFrame.AutoSize = True
Next singlecell
End Sub
The code i tried adds a comment when the information from the entry form is submitted. However I don't need the comment to show just yet, I only want it when the user changes the initial cell value.
you can use a helper array to temporary store all of current cell comments and get the sensitive text out of the last recorded comment to compare with current cell content
Private Sub Worksheet_Change(ByVal Target As Range)
Dim singleCell As Range
Dim commentsArray As Variant 'array to hold all singleCell comments
Dim oldText As String ' string to hold last comment sensitive content
If Target.Cells.CountLarge > 1000 Then Exit Sub
For Each singleCell In Target
If singleCell.Comment Is Nothing Then
singleCell.AddComment Now & " - " & singleCell.Value & " - " & Environ("UserName")
Else
commentsArray = Split(singleCell.Comment.Text, vbNewLine) ' fill the array with current singleCell comments
oldText = CStr(Split(commentsArray(UBound(commentsArray)), " - ")(1)) ' extract last recorded comment sensitive text
'update comment if current cell value differs from last recorded comment sensitive text
If oldText <> CStr(singleCell.Value2) Then _
singleCell.Comment.Text _
vbNewLine & Now & " - " & singleCell.Value & " - " & Environ("UserName") _
, Len(singleCell.Comment.Text) + 1 _
, False
End If
singleCell.Comment.Shape.TextFrame.AutoSize = True
Next
End Sub
Copy and create the same table in same sheet, have it hidden ,
Sub CopyCurrentTable()
Application.ScreenUpdating = False
With shtMapping
.Range("E4:G1000").ClearContents 'which value to which value you are copying
.Range("B4:D" & GetLastRow(shtMapping, "B", 4)).Copy ' starting postion
.Range("E4").PasteSpecial xlPasteAll
Application.CutCopyMode = False
End With
End Sub
Sub LogAuditTrail()
Dim colOld As Collection
Dim colNew As Collection
Dim objNew As ClsMapping
Dim objOld As ClsMapping
Set colOld = getMappingData("E")
Set colNew = getMappingData("B")
Dim sTS As String
sTS = Format(Now, "dd-mmm-yyy hh:mm:ss")
For Each objNew In colNew
'Detect Items Changed
If ItemIsInCollection(colOld, objNew.getKey) Then
Set objOld = colOld(objNew.getKey)
If objNew.isDifferent(objOld) Then
Call PlotToAudit(objNew, objOld, sTS, "Change")
End If
Else
'Detect Items Added
Set objOld = New ClsMapping
Call PlotToAudit(objNew, objOld, sTS, "New")
End If
Next objNew
'Detect Items removed
For Each objOld In colOld
If Not ItemIsInCollection(colNew, objOld.getKey) Then
Set objNew = New ClsMapping
Call PlotToAudit(objNew, objOld, sTS, "Removed")
End If
Next objOld
End Sub
Sub PlotToAudit(obj1 As ClsMapping, obj2 As ClsMapping, sTS As String, sType As String)
Dim lRow As Long
lRow = shtAudit.Range("B1048576").End(xlUp).Row
If lRow = 3 Then
lRow = 5
ElseIf lRow = 1048576 Then
MsgBox "Audit sheet is full. Contact Support." & vbNewLine & "No audit trail will be saved", vbCritical, "ERROR"
Exit Sub
Else
lRow = lRow + 1
End If
With shtAudit
.Unprotect g_sPassword
.Range("B" & lRow).value = Application.UserName & "(" & Environ("USERNAME") & ")"
.Range("C" & lRow).value = sTS
.Range("D" & lRow).value = sType
Select Case sType
Case "Removed"
.Range("E" & lRow).value = ""
.Range("F" & lRow).value = ""
.Range("G" & lRow).value = ""
.Range("H" & lRow).value = obj2.FundCode
.Range("I" & lRow).value = obj2.Subs
.Range("J" & lRow).value = obj2.Reds
Case "New"
.Range("E" & lRow).value = obj1.FundCode
.Range("F" & lRow).value = obj1.Subs
.Range("G" & lRow).value = obj1.Reds
.Range("H" & lRow).value = ""
.Range("I" & lRow).value = ""
.Range("J" & lRow).value = ""
Case "Change"
.Range("E" & lRow).value = obj1.FundCode
.Range("F" & lRow).value = obj1.Subs
.Range("G" & lRow).value = obj1.Reds
.Range("H" & lRow).value = obj2.FundCode
.Range("I" & lRow).value = obj2.Subs
.Range("J" & lRow).value = obj2.Reds
End Select
With .Range("B" & lRow & ":J" & lRow)
.Interior.Color = vbWhite
.Borders.LineStyle = xlContinuou
End With
.Protect g_sPassword
End With
End Sub
I am trying to vlookup few columns from another sheet, and I am trying to dynamically set range for the vlookup table and then copy and paste the formula down to my lookup values sheet (which works)
Any Help would be great!
I tried the code below but it does not set value in FRow or SRow.
Sub test()
Dim FRow As Long
Dim SRow As Long
With Sheets("M2URPN")
Set FRow = Sheets("M2URPN").Cells(Rows.Count, "A").End(xlUp).Row
End With
With Worksheets("M2URPN")
Set SRow = .sht.Cells(sht.Rows.Count, "G").End(xlUp).Row
End With
If Worksheets("RECONCILE").Range("A2") Is Nothing Then
Worksheets("RECONCILE").Range("A2").FormulaR1C1 = "NO RECORDS"
Else
With Worksheets("RECONCILE")
Range("B2").Formula = "=VLOOKUP(A2,M2URPN!$A$1:$E$" & FRow & ",4,FALSE)"
Range("B2:B" & Range("A" & Rows.Count).End(xlUp).Row).FillDown
Range("C2").Formula = "=VLOOKUP(A2,M2URPN!$A$1:$E$" & FRow & ",4,FALSE)"
Range("C2:C" & Range("A" & Rows.Count).End(xlUp).Row).FillDown
End With
End If
If Worksheets("RECONCILE").Range("E2") Is Nothing Then
Worksheets("RECONCILE").Range("E2").FormulaR1C1 = "NO RECORDS"
Else
With Worksheets("RECONCILE")
Range("F2").Formula = "=VLOOKUP(E2,M2URPN!$G$1:$J$" & SRow & ",4,FALSE)"
Range("F2:F" & Range("E" & Rows.Count).End(xlUp).Row).FillDown
Range("G2").Formula = "=VLOOKUP(E2,M2URPN!$G$1:$J$" & SRow & ",3,FALSE)"
Range("G2:G" & Range("E" & Rows.Count).End(xlUp).Row).FillDown
End With
End If
I fixed it as below:
Sub Vlookup()
Worksheets("RECONCILE").Activate
If Worksheets("RECONCILE").Range("A2") = "" Then
Worksheets("RECONCILE").Range("A2").FormulaR1C1 = "NO RECORDS"
Else
With Worksheets("RECONCILE")
Range("B2").Formula = "=VLOOKUP(A2,M2URPN!$A$1:$E$" & Sheets("M2URPN").Cells(Rows.Count, 1).End(xlUp).Row & ",4,FALSE)"
Range("B2:B" & Range("A" & Rows.Count).End(xlUp).Row).FillDown
Range("C2").Formula = "=VLOOKUP(A2,M2URPN!$A$1:$E$" & Sheets("M2URPN").Cells(Rows.Count, 1).End(xlUp).Row & ",4,FALSE)"
Range("C2:C" & Range("A" & Rows.Count).End(xlUp).Row).FillDown
Worksheets("RECONCILE").Range("B1").Value = "Amount"
Worksheets("RECONCILE").Range("C1").Value = "Customer Account"
End With
End If
If Worksheets("RECONCILE").Range("E2") = "" Then
Worksheets("RECONCILE").Range("E2").FormulaR1C1 = "NO RECORDS"
Else
With Worksheets("RECONCILE")
Range("F2").Formula = "=VLOOKUP(E2,M2URPN!$G$1:$J$" & Sheets("M2URPN").Cells(Rows.Count, 7).End(xlUp).Row & ",4,FALSE)"
Range("F2:F" & Range("E" & Rows.Count).End(xlUp).Row).FillDown
Range("G2").Formula = "=VLOOKUP(E2,M2URPN!$G$1:$J$" & Sheets("M2URPN").Cells(Rows.Count, 7).End(xlUp).Row & ",3,FALSE)"
Range("G2:G" & Range("E" & Rows.Count).End(xlUp).Row).FillDown
Worksheets("RECONCILE").Range("F1").Value = "Amount"
Worksheets("RECONCILE").Range("G1").Value = "Customer Account"
End With
End If
Worksheets("RECONCILE").Columns(2).NumberFormat = "0"
Worksheets("RECONCILE").Columns(7).NumberFormat = "0"
Range("A1:L1").Font.Bold = True
For Each sht In ThisWorkbook.Worksheets
sht.Cells.EntireColumn.AutoFit
Next sht
End Sub