I have a repetitive data reduction where I have a list of ID's that I want to find in a longer list. I have a method, but it is slower than I'd like. How can can I speed this up?
The process: After each contiguous section of ID's I want to insert a blank row (I'll do other things with the blank row but that's not important).If I have a unique list containing 10, 20, 30, 40. I want to insert a row below each of the contiguous sections of these numbers for example.
As in,
| ID | -- |
|---|---|
| 10 | |
| 10 | |
| 10 | *Insert below here |
| 15 | |
| 15 | *DO NOT INSERT HERE |
| 20 | |
| 20 | |
| 20 | *Insert below here |
| 30 | |
| 30 | *Insert below here |
| 10 | |
| 10 | |
| 10 | *Insert below here |
| 40 | *Insert below here |
I have created a way to do this, but for >40,000 lines of data and about 20 "ID's of interest" which can go for a thousand rows a piece it is not particularly efficient. Would auto filtering potentially improve efficiency or what about other methods? Storing data in array rather than using Find?
Here is an example of the module that will run on data formatted like the screenshot and workbook attached.
Option Explicit
Public Sub SummaryDataPopulate()
Dim DataWs As Worksheet: Set DataWs = ActiveSheet
Dim IDNum As Long
Dim IDCurRow As Long
Dim IDofInterestRows As Long
Dim StartRow As Long
Dim EndRow As Long
Dim Counter As Long: Counter = 0
Const IDCol As Long = 3
Application.ScreenUpdating = False
With DataWs
IDofInterestRows = .Columns("A").Cells.Find("*", SearchOrder:=xlByRows, LookIn:=xlValues, SearchDirection:=xlPrevious).Row
For IDCurRow = 3 To IDofInterestRows
IDNum = DataWs.Range("A" & IDCurRow).Value
StartRow = .Columns(IDCol).Find(IDNum).Row 'could update this in future to handle repeated ID's, currently finds first ID
EndRow = find_end_row(IDNum, StartRow, IDCol, DataWs)
'insert row & color
.Rows(EndRow + 1).Insert
.Rows(EndRow + 1).Interior.ThemeColor = xlThemeColorAccent6
'check now if there is another section
Do While ID_rerun_check(IDNum, EndRow, IDCol, DataWs) 'true if another section of same ID
StartRow = .Columns(IDCol).Find(What:=IDNum, After:=.Cells(EndRow + 2, IDCol)).Row
EndRow = find_end_row(IDNum, StartRow, IDCol, DataWs) 'new end row
'insert row & Color
.Rows(EndRow + 1).Insert
.Rows(EndRow + 1).Interior.ThemeColor = xlThemeColorAccent6
Loop
Next IDCurRow
End With
Application.ScreenUpdating = True
End Sub
Private Function ID_rerun_check(ByVal IDNum As Long, ByVal PreviousEndRow As Long, ByVal IDCol As Long, ByRef data_ws As Worksheet) As Boolean
Dim FoundRow As Long
FoundRow = data_ws.Columns(IDCol).Find(What:=IDNum, After:=data_ws.Cells(PreviousEndRow + 1, IDCol)).Row
ID_rerun_check = Not (FoundRow <= PreviousEndRow) 'false if the find has looped, 'true if find finds another section
End Function
Private Function find_end_row(ByVal IDNum As Long, ByVal StartRow As Long, ByVal IDCol As Long, ByRef data_ws As Worksheet) As Long
Dim ii As Long
Dim EndRow As Long
Dim DataRows As Long
DataRows = data_ws.Columns("C").Cells.Find("*", SearchOrder:=xlByRows, LookIn:=xlValues, SearchDirection:=xlPrevious).Row
For ii = StartRow To DataRows
EndRow = data_ws.Columns(IDCol).Find(What:=IDNum, After:=data_ws.Cells(ii, IDCol)).Row
If EndRow - 1 <> ii Then 'check if cycle back to top or if jump in value
Exit For 'exits for loop
End If
Next ii
find_end_row = ii
End Function
Here is a datafile: Sheet1 has the simple data, Sheet3 has data more realistic https://docs.google.com/spreadsheets/d/1ftCcHfiw7Sujg5L791gyn877bqmhaENy/edit?usp=sharing&ouid=111738563125877088842&rtpof=true&sd=true


DM_INSERT2UDF function in my array repo. Or, if not needed as an UDF then use theInsertRowsAtValChangethat works in any application supporting VBA. These methods also handle top and bottom rows besides the rows where value changes. There's a Demo workbook that showcases the UDF. As they are they won't handle special cases like in your example with 15 but you can add a helper column to the array and run the method on that instead. E.g. round down to multiple of ten and then just insert blank rows at value change \$\endgroup\$InsertRowsAtValChangeis FAST. The only change I had to make on my end is where you checkIf currentKey <> previousKey thenI added a nestedIfstatement:If IsNumeric(Application.Match(arr(i-1,columnIndex), inRng, 0)) ThenwhereinRngis a range variable storing the ID's of interest. They already exist printed to a sheet in a known location and it seems to work well with the Match function which is fast enough. I don't love the nest but it helps to avoid arr(i-1) when i<LBound(arr) \$\endgroup\$