Incrementing a Variable in For-loop in Vba? - excel

# This is the input table for which I want to perform some action #
Public Sub mac()
Dim RangeOfChild As Range
For i = 1 To 10000
ActiveCell.Range("A" & i).Activate
Dim DirArray As Variant
Dim temp As Variant
Set RangeOfChild = Range(ActiveCell.Offset(0, 1),ActiveCell.End(xlToRight))
childCount = RangeOfChild.count
temp = ActiveCell.Value
ActiveCell = Null
DirArray = RangeOfChild.Value
RangeOfChild.ClearContents
ActiveCell.EntireRow.Resize(childCount - 1).Insert Shift:=xlDown
ActiveCell.Value = temp
Range(ActiveCell.Offset(0, 1), ActiveCell.Offset(RangeOfChild.count - 1, 1)) = Application.Transpose(Array(DirArray))
i = i + (childCount)
Next i
End Sub
I want a output similar to the below image
enter image description here
But the written for loop is only doing the operation to two of the rows , not the remaining, If someone could help me out with this , it would be a great help.

I accomplished this task by using two worksheets: worksheets("SheetInput") which contains the input data and worksheets("SheetOutput") which receives the formatted output.
Option Explicit
Public Sub mac()
Dim wsData As Worksheet, wsOutput As Worksheet
Dim rngInput As Range, RangeOfChild As Range, rngOutput As Range
Dim childCount As Long
Set wsData = ThisWorkbook.Worksheets("SheetInput")
Set wsOutput = ThisWorkbook.Worksheets("SheetOutput")
Set rngInput = ThisWorkbook.Worksheets("SheetInput").Cells(1, 1)
Set rngOutput = ThisWorkbook.Worksheets("SheetOutput").Cells(1, 1)
While Not (IsEmpty(rngInput))
Set RangeOfChild = Range(rngInput.Offset(0, 1), rngInput.End(xlToRight))
childCount = RangeOfChild.Count
rngInput.Copy
rngOutput.PasteSpecial Paste:=xlPasteAll
RangeOfChild.Copy
rngOutput.Offset(0, 1).PasteSpecial Paste:=xlPasteAll, Transpose:=True
Set rngInput = rngInput.Offset(1, 0)
Set rngOutput = rngOutput.Offset(childCount, 0)
Wend
End Sub

activate method is not good. use a variant array.
Sub test()
Dim rngDB As Range, rngCnt As Range
Dim rng As Range, rng2 As Range
Dim vCnt, vR()
Dim i As Integer, c As Integer, n As Long, s As Long
Set rngDB = Range("a1", Range("a" & Rows.Count).End(xlUp))
For Each rng In rngDB
Set rngCnt = Range(rng.Offset(, 1), rng.End(xlToRight))
s = n + 1
vCnt = rngCnt
c = rngCnt.Columns.Count
n = n + c
ReDim Preserve vR(1 To 2, 1 To n)
vR(1, s) = rng
For i = 1 To c
vR(2, s + i - 1) = vCnt(1, i)
Next i
Next rng
Sheets.Add
Range("a1").Resize(n, 2) = WorksheetFunction.Transpose(vR)
End Sub

Related

Copy visible cells to extract listobject filtered data to a new workbook

I am trying to extract listobject filtered data to a new workbook. However, all data is extracted instead of just the filtered data.
Set loop_obj = wsCopy.ListObjects(1)
loop_obj.AutoFilter.ShowAllData
ColNum = Application.WorksheetFunction.Match("DateOrder", wsCopy.Rows(1), 0)
With loop_obj
.Range.AutoFilter Field:=ColNum, Criteria1:=">=0"
End With
'Add Copy Values to Array
Set loop_copy = loop_obj.AutoFilter.Range.SpecialCells(xlCellTypeVisible)
arr = loop_copy.CurrentRegion.Offset(1, 0)
aRws = Evaluate("Row(1:" & UBound(arr) & ")")
arr = Application.Index(arr, aRws, Array(1, 2, 3, 4, 5))
'Create New Workbook with a Blank Worksheet
wb.Worksheets.Add.Move
Set wb_new = ActiveWorkbook
Set wsDest = ActiveWorkbook.ActiveSheet
'Perform Paste Operations
Set loop_paste = wsDest.Range("A1")
loop_paste.Resize(UBound(arr, 1), UBound(arr, 2)).value = arr
With wsDest
.Range(Cells(1, DateNum), Cells(1200, DateNum)).NumberFormat = "[$-en-US]d-mmm-yy;#"
.Parent.SaveAs FileName:=dFilePath, FileFormat:=xlCSVUTF8
.Parent.Close True
End With
loop_obj.AutoFilter.ShowAllData
This worked for me (just copy each column based off the array of column indexes):
Sub tester()
Dim wsCopy As Worksheet, loop_copy As Range
Dim loop_obj As ListObject, colnum As Long
Dim col, visRows As Long, rngDest As Range, i As Long
Set wsCopy = Sheets("Details")
Set loop_obj = wsCopy.ListObjects(1)
loop_obj.AutoFilter.ShowAllData
colnum = Application.Match("DateOrder", loop_obj.HeaderRowRange, 0)
If IsError(colnum) Then
MsgBox "Header not found!"
Exit Sub
End If
Application.ScreenUpdating = False
loop_obj.Range.AutoFilter Field:=colnum, Criteria1:=">=0"
On Error Resume Next 'in case no visible rows to count
visRows = loop_obj.DataBodyRange.Columns(1).SpecialCells(xlCellTypeVisible).Count
On Error GoTo 0
If visRows > 0 Then
Set rngDest = Sheets("destination").Range("B2")
i = 0
For Each col In Array(1, 2, 3, 4, 5)
loop_obj.DataBodyRange.Columns(col).SpecialCells(xlCellTypeVisible).Copy
rngDest.Parent.Paste Destination:=rngDest.Offset(0, i)
i = i + 1
Next col
End If
loop_obj.AutoFilter.ShowAllData
End Sub
EDIT: a different array-based approach - this is faster, but again it's more complex, so there's a trade-off.
Sub Tester()
Dim wsCopy As Worksheet, loop_copy As Range
Dim loop_obj As ListObject, colnum As Long
Dim col, visRows As Long, rngDest As Range, i As Long, data
Set wsCopy = Sheets("Details")
Set loop_obj = wsCopy.ListObjects(1)
loop_obj.AutoFilter.ShowAllData
colnum = Application.Match("DateOrder", loop_obj.HeaderRowRange, 0)
If IsError(colnum) Then
MsgBox "Header not found!"
Exit Sub
End If
Application.ScreenUpdating = False
loop_obj.Range.AutoFilter Field:=colnum, Criteria1:=">=0"
data = arrayFromVisibleRows(loop_obj.DataBodyRange)
If Not IsEmpty(data) Then
With Sheets("Destination").Range("B2")
.CurrentRegion.ClearContents
.Resize(UBound(data, 1), UBound(data, 2)).Value = data
End With
End If
loop_obj.AutoFilter.ShowAllData
End Sub
'Return a 2D array using only visible row in `rng`
' Optionally include only column indexes in `cols` (passed as a 1D array)
Function arrayFromVisibleRows(rng As Range, Optional cols As Variant = Empty)
Dim rngVis As Range, data, dataOut
Dim rw As Long, col, e, c As Range, cOut As Long, rOut As Long, srcRow As Long
On Error Resume Next
Set rngVis = rng.Columns(1).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If Not rngVis Is Nothing Then
data = rng.Value 'read all the range data to an array
If IsEmpty(cols) Then
'create an array with all column indexes if none were provided
cols = Application.Transpose(Evaluate("=ROW(1:" & rng.Columns.Count & ")"))
End If
'size the output array
ReDim dataOut(1 To rngVis.Cells.Count, 1 To (UBound(cols) - LBound(cols)) + 1)
rOut = 1
For Each c In rngVis.Cells
cOut = 1
srcRow = 1 + (c.Row - rng.Cells(1).Row)
For Each col In cols 'loop the required columns
dataOut(rOut, cOut) = data(srcRow, col)
cOut = cOut + 1
Next col
rOut = rOut + 1
Next c
arrayFromVisibleRows = dataOut
Else
arrayFromVisibleRows = Empty
End If
End Function
I think that this is close to what the OP wants. I didn't bother saving the file because its not relevant to my test and I added column headers.
Sub Main()
Dim tCopyTable As ListObject
Set tCopyTable = wsCopy.ListObjects(1)
Dim DateOrder As ListColumn
Dim Source As Range
With tCopyTable
If Not .AutoFilter Is Nothing Then .AutoFilter.ShowAllData
Set DateOrder = tCopyTable.ListColumns("DateOrder")
.Range.AutoFilter Field:=DateOrder.Index, Criteria1:=">=0"
Set Source = .Range.Offset(1)
End With
Dim CountOfVisibleDates As Long
CountOfVisibleDates = WorksheetFunction.Subtotal(103, Source.Columns(DateOrder.Index))
If CountOfVisibleDates > 0 Then
Dim wb As Workbook
Set wb = Workbooks.Add
With wb.Worksheets(1)
tCopyTable.HeaderRowRange.Resize(1, 5).Copy .Range("A1")
Source.Resize(, 5).Copy .Range("A2")
End With
End If
End Sub
Note: Looping through the values is almost always much faster than copying ranges.
Addendum
Sub Main2()
Dim tCopyTable As ListObject
Set tCopyTable = wsCopy.ListObjects(1)
Dim DateOrder As ListColumn
Dim Source As Range
With tCopyTable
If Not .AutoFilter Is Nothing Then .AutoFilter.ShowAllData
Set DateOrder = tCopyTable.ListColumns("DateOrder")
.Range.AutoFilter Field:=DateOrder.Index, Criteria1:=">=0"
Set Source = .Range.Offset(1)
End With
Dim CountOfVisibleDates As Long
CountOfVisibleDates = WorksheetFunction.Subtotal(103, Source.Columns(DateOrder.Index))
Dim OriginalColumnOrder As Variant
Dim NewColumnOrder As Variant
OriginalColumnOrder = Array(1, 2, 3, 4, 5)
NewColumnOrder = Array(3, 2, 1, 5, 4)
Dim c As Long
If CountOfVisibleDates > 0 Then
Dim wb As Workbook
Set wb = Workbooks.Add
With wb.Worksheets(1)
For c = 0 To UBound(NewColumnOrder)
tCopyTable.HeaderRowRange.Columns(OriginalColumnOrder(c)).Copy .Rows(1).Columns(NewColumnOrder(c))
Source.Resize(, 5).Columns(OriginalColumnOrder(c)).Copy .Rows(2).Columns(NewColumnOrder(c))
Next
End With
End If
End Sub
Result
I was in a rush. This is all that is needed to copy the headers and filtered data:
tCopyTable.ListColumns(OriginalColumnOrder(c)).Range.Copy .Rows(1).Columns(NewColumnOrder(c))
If you just want the data use:
tCopyTable.ListColumns(OriginalColumnOrder(c)).DataBodyRange.Copy .Rows(1).Columns(NewColumnOrder(c))

Matching 2 Separate Strings with 2 Separate Ranges to Copy the Corresponding Value

I have been trying to match Date with week number i.e. ("B1:F1")
then date with Year-month i.e. ("A2:A500")
If matches then copy the value from this table that i have highlighted according to the date which is available in code where week is 2 and month is May-2021. Can someone please help me to achieve this.
There are multiple dates which i need to iterate with this table to get different values according to weeks and Year-Months.
Your help will be much appreciated.
Sub findMatchingRecords()
Dim rng1 As Range
Dim rng2 As Range
Dim ws As Worksheet
Dim getdate As String
Dim GetWeek As String
Set ws = Worksheets("Sheet1")
getdate = ws.Range("N1").Value
GetWeek = Int((Day(getdate) + 6) / 7)
Set rng1 = ws.Range("B1:F1")
Set rng2 = ws.Range("A2:A500")
For Each rng1cell In rng1
For Each rng2cell In rng2
If rng1cell = GetWeek And rng2cell = Format(getdate, "yyyy-mmm") Then
'Copy value and paste into Sheet1.Range("M2")
End If
Next rng1cell
Next rng2cell
End Sub
Here are the dates which needs to match with table and get relevant the value.
5/13/2021
5/16/2021
5/19/2021
5/22/2021
5/25/2021
5/28/2021
5/31/2021
6/3/2021
6/6/2021
6/9/2021
6/12/2021
6/15/2021
6/18/2021
6/21/2021
6/24/2021
Non-VBA Method
One way this could be done without using VBA is with a INDEX/MATCH formula.
The following formula assumes the data is in B2:F500, the month/years are in A2:A500, the weeks in B1:F1 and the dates to look for are in column N, all on the same sheet Sheet1.
=INDEX($B$2:$F$13,MATCH(TEXT(N1,"yyyy-mmm"),Sheet1!$A$2:$A$13,0),MATCH(INT((DAY(N1)+6)/7),Sheet1!$B$1:$F$1,0))
VBA Method
If you want VBA to do this here's one way.
Option Explicit
Sub findMatchingRecords()
Dim ws As Worksheet
Dim rngData As Range
Dim rngDates As Range
Dim arrData As Variant
Dim arrDates As Variant
Dim arrYearMonth As Variant
Dim arrValues As Variant
Dim arrWeeks As Variant
Dim Res As Variant
Dim idxCol As Long
Dim idxDate As Long
Dim idxRow As Long
Dim wk As Long
Set ws = Sheets("Sheet1")
With ws
Set rngData = .Range("A1").CurrentRegion
Set rngDates = .Range("N1", .Range("N" & Rows.Count).End(xlUp))
End With
With rngData
arrData = rngData.Offset(1, 1).Resize(.Rows.Count - 1, .Columns.Count - 1)
arrYearMonth = .Columns(1).Offset(1).Resize(.Rows.Count - 1)
arrWeeks = .Rows(1).Offset(, 1).Resize(, .Columns.Count - 1)
End With
arrDates = rngDates.Value
ReDim arrValues(1 To UBound(arrDates, 1), 1 To 1)
For idxDate = LBound(arrDates, 1) To UBound(arrDates, 1)
idxRow = 0
idxCol = 0
Res = Application.Match(Format(arrDates(idxDate, 1), "yyyy-mmm"), arrYearMonth, 0)
If Not IsError(Res) Then
idxRow = Res
wk = Int((Day(arrDates(idxDate, 1)) + 6) / 7)
Res = Application.Match(wk, arrWeeks, 0)
If Not IsError(Res) Then
idxCol = Res
End If
End If
If idxRow <> 0 And idxCol <> 0 Then
arrValues(idxDate, 1) = arrData(idxRow, idxCol)
End If
Next idxDate
rngDates.Offset(, 1).Value = arrValues
End Sub
Please, test the next code:
Sub MatchDate_WeekNo()
Dim sh As Worksheet, lastR As Long, arr, arrN, arrfin, i As Long, strDate As String
Dim weekN As Long, arrRow, arrCol, iCol As Variant, iRow As Variant, lastRN As Long
Set sh = Worksheets("Sheet1")
lastR = sh.Range("A" & sh.Rows.Count).End(xlUp).Row
lastRN = sh.Range("N" & sh.Rows.Count).End(xlUp).Row
arr = sh.Range("A1:F" & lastR).Value
arrRow = Application.Index(arr, 1, 0)
arrCol = Application.Transpose(Application.Index(arr, 0, 1))
arrN = sh.Range("N2:N" & lastRN).Value2
ReDim arrfin(1 To UBound(arrN), 1 To 1)
For i = 1 To UBound(arrN)
strDate = StringFromDate(CDate(arrN(i, 1)))
weekN = Int((Day(arrN(i, 1)) + 6) / 7)
iCol = Application.Match(weekN, arrRow, 0)
iRow = Application.Match(strDate, arrCol, 0)
If IsNumeric(iCol) And IsNumeric(iRow) Then
arrfin(i, 1) = arr(iRow, iCol)
End If
Next i
'drop the final array content:
sh.Range("O2").Resize(UBound(arrfin), 1).Value = arrfin
End Sub
Function StringFromDate(d As Date) As String
Dim arrM
Const strMonths As String = "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec"
arrM = Split(strMonths, ",")
StringFromDate = Year(d) & "-" & Application.Index(arrM, Month(d))
End Function
Format(arrDates(idxDate, 1), "yyyy-mmm") does not return the month in case of localization different then English type and only that's why I am using a function...

Fillfdown Approach for an index match function via VBA

with the given code I am trying hard incorporate the Filldown approach until the last row but at present whatever I do only fills row number 1:
Sub FillDownApproach()
Dim destinationWs As Worksheet
Dim destinationLastRow As Long
Set destinationWs = ThisWorkbook.Worksheets("Main Board")
destinationLastRow = destinationWs.Range("A" & Rows.Count).End(xlUp).Row
RetVal = destinationWs.Evaluate("INDEX('MyData'!$E:$E,MATCH(1,($A2='MyData'!$B:$B)*(""MyItem""='MyData'!$D:$D),0))")
destinationWs.Range("C2").Value = RetVal
destinationWs.Range("C3: " & "C" & destinationLastRow).FillDown
End Sub
Any suggestion that could point towards the right direction.
Thanks
You cannot do what you want without looping. And Looping ranges is slow.
Instead load Variant arrays and loop them.
Sub FillDownApproach()
Dim destinationWs As Worksheet
Set destinationWs = ThisWorkbook.Worksheets("Main Board")
Dim destinationLastRow As Long
destinationLastRow = destinationWs.Range("A" & Rows.Count).End(xlUp).Row
Dim lkpArr As Variant
lkpArr = destinationWs.Range("A2:A" & destinationLastRow).Value
With Worksheets("MyData")
Dim retval As Variant
retval = Intersect(.Range("E:E"), .UsedRange)
Dim mtch As Variant
mtch = Intersect(.Range("B:D"), .UsedRange)
End With
Dim outArr As Variant
ReDim outArr(1 To UBound(lkpArr, 1), 1 To 1)
Dim i As Long
For i = 1 To UBound(lkpArr, 1)
Dim j As Long
For j = 1 To UBound(retval, 1)
If mtch(j, 3) = "MyItem" Then
If mtch(j, 1) = lkpArr(i, 1) Then
outArr(i, 1) = retval(j, 1)
Exit For
End If
End If
Next j
Next i
destinationWs.Range("C2").Resize(UBound(outArr, 1), 1).Value = outArr
End Sub

Manipulating Columns VBA

I have got below coding for my huge data set VBA, I wish to manipulate columns according to my range criteria, Please help.
Dim Ary As Variant, Nary As Variant
Dim r As Long, Rw As Long
With Sheets("Sheet1")
Ary = .Range("A2:B" & .Range("A" & Rows.Count).End(xlUp).Row).Value2
End With
ReDim Nary(1 To UBound(Ary), 1 To 1)
With CreateObject("scripting.dictionary")
For r = 1 To UBound(Ary)
If Not .Exists(Ary(r, 1)) Then
.Add Ary(r, 1), r
Nary(r, 1) = Ary(r, 2)
Else
Rw = .Item(Ary(r, 1))
Nary(Rw, 1) = Nary(Rw, 1) + Ary(r, 2)
End If
Next r
End With
Sheets("sheet1").Range("C2").Resize(UBound(Nary)).Value = Nary
Sheets("sheet1").Range("C2").Resize(UBound(Nary)).Value = Nary
I want to columns re-arrange as per below criteria,
ColumnA = ColumnD (4)
ColumnB = ColumnN (14)
ColumnC - ColumnO (15)
Please re-codes above Ubound & Lbound coding as per above criteria, As I am not far used to with arrays
functions codes.
Above coding are working fine I just want to manipulate columns.
Thankyou
Get First Sums
The following sums up the values in a column for each unique value in another column and displays the result in a third column in the rows of the first occurrence of each unique value.
Option Explicit
Function getFirstSums( _
ws As Worksheet, _
ByVal LookUpColumn As Variant, _
ByVal ValuesColumn As Variant, _
Optional ByVal FirstRow As Long = 1) _
As Variant
Dim LastRow As Long
LastRow = ws.Cells(ws.Rows.Count, LookUpColumn).End(xlUp).Row
Dim rng As Range
Set rng = ws.Cells(FirstRow, LookUpColumn).Resize(LastRow - FirstRow + 1)
Dim Lookup As Variant: Lookup = rng.Value
Dim SumUp As Variant
SumUp = rng.Offset(, ws.Columns(ValuesColumn).Column _
- ws.Columns(LookUpColumn).Column).Value
Dim rCount As Long: rCount = UBound(Lookup)
Dim Result As Variant: ReDim Result(1 To rCount, 1 To 1)
Dim r As Long, rw As Long
With CreateObject("Scripting.Dictionary")
For r = 1 To rCount
If Not .Exists(Lookup(r, 1)) Then
.Add Lookup(r, 1), r
Result(r, 1) = SumUp(r, 1)
Else
rw = .Item(Lookup(r, 1))
Result(rw, 1) = Result(rw, 1) + SumUp(r, 1)
End If
Next r
End With
getFirstSums = Result
End Function
Sub TESTgetFirstSums()
Const wsName As String = "Sheet1"
Const LookUpColumn As Variant = "D"
Const ValuesColumn As Variant = "N"
Const ResultColumn As Variant = "O"
Const FirstRow As Long = 2
Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets("Sheet1")
Dim ary As Variant
ary = getFirstSums(ws, LookUpColumn, ValuesColumn, FirstRow)
ws.Range(ResultColumn & FirstRow).Resize(UBound(ary)).Value = ary
End Sub
Sub TESTgetFirstSumsSimple()
Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets("Sheet1")
Dim ary As Variant
ary = getFirstSums(ws, 4, 14, 2)
ws.Cells(2, 15).Resize(UBound(ary)).Value = ary
End Sub
EDIT:
Or you might rather write it as a sub procedure:
Sub writeFirstSums( _
ws As Worksheet, _
ByVal LookUpColumn As Variant, _
ByVal ValuesColumn As Variant, _
ByVal ResultColumn As Variant, _
Optional ByVal FirstRow As Long = 1)
Dim LastRow As Long
LastRow = ws.Cells(ws.Rows.Count, LookUpColumn).End(xlUp).Row
Dim rng As Range
Set rng = ws.Cells(FirstRow, LookUpColumn).Resize(LastRow - FirstRow + 1)
Dim Lookup As Variant: Lookup = rng.Value
Dim SumUp As Variant
SumUp = rng.Offset(, ws.Columns(ValuesColumn).Column _
- ws.Columns(LookUpColumn).Column).Value
Dim rCount As Long: rCount = UBound(Lookup)
Dim Result As Variant: ReDim Result(1 To rCount, 1 To 1)
Dim r As Long, rw As Long
With CreateObject("Scripting.Dictionary")
For r = 1 To rCount
If Not .Exists(Lookup(r, 1)) Then
.Add Lookup(r, 1), r
Result(r, 1) = SumUp(r, 1)
Else
rw = .Item(Lookup(r, 1))
Result(rw, 1) = Result(rw, 1) + SumUp(r, 1)
End If
Next r
End With
ws.Cells(FirstRow, ResultColumn).Resize(UBound(Result)) = Result
End Sub
Sub TESTwriteFirstSumsSimple()
Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets("Sheet1")
writeFirstSums ws, 4, 14, 15, 2
End Sub

Moving columns containg "Total" at the end of the pivot(after paste special) if the cells of second row contain the word "Total"

' If the cells of second row contain the word "Total" ,I want to copy paste the entire column of that cell to the end of the table.The following code gives no output. Can someone please help me identify my mistake?
enter image description here
Dim PRTSLastRow As Long
Dim PRTSLastCol As Long
Dim ColLtr As String
Dim LastColLtr As String
Dim Total As String
Dim j as Integer
W = ActiveWorkbook.Name
PRTSLastCol = Worksheets("PRTSCarrierCount").Cells(1, Columns.Count).End(xlToLeft).Column
PRTSLastRow = Worksheets("PRTSCarrierCount").Cells(Rows.Count, 1).End(xlUp).Row
j = 1
Workbooks(W).Sheets("PRTSCarrierCount").Activate
For i = 1 To PRTSLastCol
Total = Cells(1, i).Value
If InStr(1, CStr(Total), "Total") > 0 Then
ColLtr = Replace(Cells(1, i).Address(True, False), "$1", "")
LastColLtr = Replace(Cells(1, PRTSLastCol + j).Address(True, False), "$1", "")
Range("ColLtr & 1: & ColLtr & PRTSLastRow").Select
'Columns("ColLtr & : & ColLtr").Select
Selection.Copy
Range("LastColLtr & 1").Select
ActiveSheet.Paste
j = j + 1
End If
Next i
Something like this?
Option Explicit
Sub Thing()
Dim PRTSLastRow As Long
Dim PRTSLastCol As Long
Dim ColLtr As String
Dim LastColLtr As String
Dim Total As String
Dim W As Workbook
Dim i As Long
Dim ws As Worksheet
Set W = ThisWorkbook 'Or ActiveWorkbook
Set ws = W.Worksheets("PRTSCarrierCount")
PRTSLastRow = ws.Cells(Rows.Count, 1).End(xlUp).Row
PRTSLastCol = GetLastCol(ws, 1)
With ws
For i = 1 To PRTSLastCol
Total = LCase$(.Cells(1, i).Text)
If InStr(1, Total, "total") > 0 Then
ColLtr = Replace(.Cells(1, i).Address(True, False), "$1", "")
.Range(ColLtr & "1:" & ColLtr & PRTSLastRow).Copy .Cells(1, GetLastCol(ws, 1) + 1)
i = i + 1
End If
Next i
End With
End Sub
Public Function GetLastCol(ByVal ws As Worksheet, rowNum As Long) As Long
With ws
GetLastCol = .Cells(rowNum, Columns.Count).End(xlToLeft).Column
End With
End Function
Or with Find
Public Sub Thing2()
Dim PRTSLastRow As Long
Dim PRTSLastCol As Long
Dim ColLtr As String
Dim LastColLtr As String
Dim Total As String
Dim W As Workbook
Dim ws As Worksheet
Dim searchRng As Range
Set W = ThisWorkbook 'Or ActiveWorkbook
Set ws = W.Worksheets("PRTSCarrierCount")
PRTSLastCol = GetLastCol(ws, 1)
Total = "total"
With ws
PRTSLastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
Set searchRng = .Range(.Cells(1, 1), .Cells(1, PRTSLastCol))
Dim gatheredRange As Range
Set gatheredRange = GatherRanges(Total, searchRng, PRTSLastRow)
If Not gatheredRange Is Nothing Then
gatheredRange.Copy .Cells(1, GetLastCol(ws, 1) + 1)
End If
End With
End Sub
Public Function GatherRanges(ByVal Total As String, ByVal searchRng As Range, ByVal PRTSLastRow As Long) As Range
Dim foundCell As Range
Set foundCell = searchRng.Find(Total)
If foundCell Is Nothing Then
MsgBox "Search term not found"
End
End If
Dim firstfoundCellAddress As String
firstfoundCellAddress = foundCell.Address
Dim gatheredRange As Range
Set gatheredRange = foundCell.Resize(PRTSLastRow, 1)
Do
Set foundCell = searchRng.FindNext(foundCell)
Set gatheredRange = Union(gatheredRange, foundCell.Resize(PRTSLastRow, 1))
Loop While firstfoundCellAddress <> foundCell.Address
Set GatherRanges = gatheredRange
End Function
Reference:
https://excelmacromastery.com/excel-vba-find/

Resources