Reputation: 5543
I'm trying to return the nth visible element of a filtered table in Excel. Current methods tell me to use the SpecialCells(xlCellTypeVisible)
method, then loop through the elements whilst counting them with a For Each... Next
loop.
This seems sub-optimal; I don't want to know about the first 19 ranges, only the 20th. Is there any way to skip straight to the 20th element of a loop?
Or maybe loop through the .Areas
and count their sizes; meaning you only need to step into the Area
which contains the nth element, then sub-loop within that area to locate the element precisely. Would this be faster?
Of course, if you can think of a better way to get the nth element of a filtered table, that'd be good too!
My code to get the table range is:
Dim inptTbl As Range
Set inptTbl = ThisWorkbook.Sheets("compiled").ListObjects("Table2").ListColumns("Company").Range.SpecialCells(xlCellTypeVisible)
Then to loop through, well I haven't written that yet, but I guess:
i=0
Dim r As Range
For Each r in inptTbl
i=i+1
If i = 20 Then Exit For
Next r
Debug.Print r.Address
Looping through areas as described:
Set inptTbl = ThisWorkbook.Sheets("compiled").ListObjects("Table2")
Set test = inptTbl.ListColumns("Company").Range.SpecialCells(xlCellTypeVisible)
runningTot = 0
arIndex = 1
Do Until test.Areas(arIndex).Cells.Count + runningTot > 20
runningTot = runningTot + test.Areas(arIndex).Cells.Count
arIndex = arIndex + 1
Loop
i = 0
Dim r As Range
For Each r In test.Areas(arIndex)
If i = 20 - runningTot Then Exit For
i = i + 1
Next r
Debug.Print r.Address
Upvotes: 3
Views: 594
Reputation: 12113
Final Update
As you mentioned you are looking for the most efficient way to go, I'd loop through the areas rather than individual cells.
Sub test2()
Dim a As Range, rng As Range
Dim n As Long, total As Long, adj As Long
n = 20
Set rng = ThisWorkbook.Worksheets("Sheet1").Range("A1:A1000").SpecialCells(xlCellTypeVisible)
For Each a In rng.Areas
adj = n - total
total = total + a.Cells.Count
If total >= n Then
Debug.Print a.Cells(adj, 1).Address
Exit Sub
End If
Next a
End Sub
In the interest of keeping this answer relatively clean, I deleted my previous efforts.
Finally, and still using xlCellTypeVisible
, this should work in any case. It adjusts the size of your range until there are 20 visible cells and then returns the last cell in that range.
Sub test()
Dim rng As Range, r As Range
Dim n As Long
n = 20 'update for your required value of n
With ThisWorkbook.Worksheets("Sheet1") 'relevant sheet name
Set r = .Range("A1") 'where to start?
Set rng = r.Resize(n, 1)
End With
While rng.SpecialCells(xlCellTypeVisible).Count < n
Set rng = rng.Resize(rng.Rows.Count + 1, 1)
Wend
Debug.Print rng.Cells(rng.Rows.Count + r.Row - 1, r.Column).Address
End Sub
Upvotes: 2
Reputation:
A filtered range could have many discontiguous Areas (see Get Excel filter results into VBA array). If you are looping through the visible cells, then use areas but if yu want to jump to the 20th visible elemen t, just run through a For Next loop until you meet the extent you want to retrieve.
Dim r As Long, v As Long
v = 20
With Selection
For r = 1 To .Rows.Count
v = v + (Not .Cells(r).EntireRow.Hidden)
If v = 0 Then Exit For
Next r
Debug.Print .Cells(r).Value
End With
I've used Selection
here for expediency; you can retrieve the actual cell range from your table.
Upvotes: 2
Reputation: 3791
Would need to see your full code ideally, but instead of using For Each....Next
, you could count the visible cells and do something like
Sub test()
Dim vcells as Long
vcells = Activesheet.Usedrange.SpecialCells(xlCellTypeVisible).Rows.Count
For i = 20 to vcells
`your code here
Next i
End Sub
Upvotes: 1