excelvbaloopsdynamicrange

VBA set a dynamic range based on “unique” IDs in a column


enter image description here

I want to give a "timepoint" value (which I call a "scanRank" in the code below) to all the rows in this table based on "Subject ID". In this picture, the first subject is already completed. What I want to do is have VBA recognize the first row and the last row for each "unique" Subject ID. I put "unique" in quotes because I don't want to "find" the unique IDs, I just want the macro to stop the range when the Subject ID changes. Then once the macro has those cell addresses for the start and end, then it can run the for loop to get the "timepoints" for each subject ID then move on to the next subject ID. In the code below, I don't know how to code the "startSubID", "endSubID", "scanRow", or "prevscanRow" variables. I was thinking of using some kind of do loop, but I can't wrap my head around how it would work. Please help, thank you!

Private Sub CommandButton1_Click()

Dim ws4 As Worksheet
Set ws4 = ThisWorkbook.Sheets("Sheet1") ' Change "Sheet1" to your sheet name
  
Dim ScanDates As Range, SingScanDate As Range
Dim SubIDs As Range, UniqueSubID As Range

lastrow = ws4.Cells(ws4.Rows.Count, 3).End(xlUp).Row
Set SubIDs = ws4.Range("C12:C" & lastrow)


For Each UniqueSubID In SubIDs
 '   startSubID = ??? starting row based on Subject ID in Column C
 '   endSubID = ??? ending row based on Subject ID in Column C
 
Set ScanDates = ws4.Range(ws4.Cells(startSubID, 6), ws4.Cells(endSubID, 6))

scanRank = 1
scanRow = startSubID.Address
prevscanRow = startSubID.Address.Offset(1, 0)

For Each SingScanDate In ScanDates
    ws4.Cells(scanRow, 6).Value = scanRank
    If ws4.Cells(scanRow, 5).Value = ws4.Cells(prevscanRow, 5).Value Then
    ws4.Cells(scanRow, 6).Value = ws4.Cells(prevscanRow, 6).Value
    End If
    scanRow = scanRow + 1
    prevscanRow = prevscanRow + 1
    scanRank = scanRank + 1
    
Next SingScanDate
  UniqueSubID = endSubID + 1
  Next UniqueSubID

End Sub

enter image description here


Solution

  • Something like this maybe:

    Option Explicit
    
    Private Sub CommandButton1_Click()
    
        Dim ws4 As Worksheet, c As Range, subjId As String, currSubjId As String
        Dim dt As Date, currDt As Date, scanRank As Long
        
        Set ws4 = ThisWorkbook.Sheets("Sheet1")
        currSubjId = vbTab 'not a valid id...
        
        For Each c In ws4.Range("C12:C" & ws4.Cells(Rows.Count, "C").End(xlUp).Row).Cells
            subjId = c.Value                      'subject id
            dt = c.EntireRow.Columns("E").Value   'scan date
            
            If subjId <> currSubjId Then     'new subject?
                scanRank = 1
                currDt = dt
                currSubjId = subjId
            ElseIf dt <> currDt Then         'same subject but new date?
                scanRank = scanRank + 1      'increment the counter
                currDt = dt
            End If
            
            c.EntireRow.Columns("F").Value = scanRank  'assign the counter to this row
        
        Next c
        
    End Sub
    

    Formula version (in F12 then fill down):

    =IF(COUNTIF(C$12:C12,C12)=1,1,IF(E12<>E11,F11+1,F11))