Function getFilteredRows(ByRef rngFilter As Range, _
Optional bHeader As Boolean, _
Optional oSheet As Worksheet) As Variant
Dim shNew As Worksheet
Dim lRowCount As Long
Dim lColCount As Long
Dim arr
If oSheet Is Nothing Then
Set oSheet = ActiveSheet
End If
If oSheet.FilterMode = False Then
'early exit if the sheet has no active filter
'--------------------------------------------
getFilteredRows = rngFilter
Exit Function
End If
Application.ScreenUpdating = False
lColCount = rngFilter.Columns.Count
lRowCount = rngFilter.SpecialCells(xlCellTypeVisible).Cells.Count \
lColCount
For Each shNew In ActiveWorkbook.Worksheets
If shNew.Name = "ZYQYZ" Then
shNew.Delete
End If
Next shNew
Set shNew = ActiveWorkbook.Sheets.Add
shNew.Name = "ZYQYZ"
rngFilter.Copy Sheets("ZYQYZ").Cells(1)
With Sheets("ZYQYZ")
If bHeader Then
arr = .Range(.Cells(2, 1), .Cells(lRowCount, lColCount))
Else
arr = .Range(.Cells(1), .Cells(lRowCount, lColCount))
End If
Application.DisplayAlerts = False
.Delete
Application.DisplayAlerts = True
End With
Application.ScreenUpdating = True
getFilteredRows = arr
End Function
One way would be just looping through the filtered range and only put values
in the array
of rows that are not hidden, but that is a lot slower than the above code.
RBS
Function getFilteredRows(ByRef rngFilter As Range, _
Optional bHeader As Boolean, _
Optional oSheet As Worksheet) As Variant
Dim shNew As Worksheet
Dim lRowCount As Long
Dim lColCount As Long
Dim arr
If oSheet Is Nothing Then
Set oSheet = ActiveSheet
End If
If oSheet.FilterMode = False Then
'early exit if the sheet has no active filter
'--------------------------------------------
getFilteredRows = rngFilter
Exit Function
End If
Application.ScreenUpdating = False
lColCount = rngFilter.Columns.Count
lRowCount = rngFilter.SpecialCells(xlCellTypeVisible).Cells.Count \
lColCount
Set shNew = ActiveWorkbook.Sheets.Add
rngFilter.Copy shNew.Cells(1)
With shNew
If bHeader Then
arr = .Range(.Cells(2, 1), .Cells(lRowCount, lColCount))
Else
arr = .Range(.Cells(1), .Cells(lRowCount, lColCount))
End If
Application.DisplayAlerts = False
.Delete
Application.DisplayAlerts = True
End With
Application.ScreenUpdating = True
getFilteredRows = arr
End Function
RBS
"RB Smissaert" <bart.sm...@gmail.com> wrote in message
news:i45n7g$i9b$1...@news.eternal-september.org...
Function getFilteredRows(ByRef rngFilter As Range, _
Optional bHeader As Boolean, _
Optional oSheet As Worksheet) As Variant
Dim shNew As Worksheet
Dim lRowCount As Long
Dim lColCount As Long
If oSheet Is Nothing Then
Set oSheet = ActiveSheet
End If
If oSheet.FilterMode = False Then
'early exit if the sheet has no active filter
'--------------------------------------------
getFilteredRows = rngFilter
Exit Function
End If
Application.ScreenUpdating = False
lColCount = rngFilter.Columns.Count
lRowCount = rngFilter.SpecialCells(xlCellTypeVisible).Cells.Count \
lColCount
Set shNew = ActiveWorkbook.Sheets.Add
rngFilter.Copy shNew.Cells(1)
With shNew
If bHeader Then
getFilteredRows = .Range(.Cells(2, 1), .Cells(lRowCount, lColCount))
Else
getFilteredRows = .Range(.Cells(1), .Cells(lRowCount, lColCount))
End If
Application.DisplayAlerts = False
.Delete
Application.DisplayAlerts = True
End With
Application.ScreenUpdating = True
End Function
RBS
"RB Smissaert" <bart.sm...@gmail.com> wrote in message
news:i45o5c$pj4$1...@news.eternal-september.org...
Function getFilteredRows(rngFilter As Range, _
Optional bOmitHeader As Boolean, _
Optional oSheet As Worksheet) As Variant
Dim shNew As Worksheet
If oSheet Is Nothing Then
Set oSheet = ActiveSheet
End If
If oSheet.FilterMode = False Then
'early exit if the sheet has no active filter
'--------------------------------------------
getFilteredRows = rngFilter
Exit Function
End If
Application.ScreenUpdating = False
Set shNew = ActiveWorkbook.Sheets.Add
rngFilter.Copy shNew.Cells(1)
With shNew
If bOmitHeader Then
getFilteredRows = .Range(.Cells(2, 1), .Cells(2,
1).SpecialCells(xlLastCell))
Else
getFilteredRows = .UsedRange
End If
Application.DisplayAlerts = False
.Delete
Application.DisplayAlerts = True
End With
Application.ScreenUpdating = True
End Function
RBS
"RB Smissaert" <bart.sm...@gmail.com> wrote in message
news:i45ohn$sge$1...@news.eternal-september.org...
'The range address has a length limitation of ~ 256 characters.
'So the following only works on a small filtered range.
'You must specify the filtered column number.
strFilterAddress = ActiveSheet.AutoFilter.Range.Columns(1).SpecialCells(xlCellTypeVisible).Address
vFilterRange = VBA.Split(strFilterAddress, ",", -1, vbBinaryCompare)
x = LBound(vFilterRange, 1)
y = UBound(vFilterRange, 1)
MsgBox "Lower bound is: " & x & vbCr & "Upper bound is: " & y
vFilterRange = VBA.Join(vFilterRange, ":")
vFilterRange = VBA.Split(vFilterRange, ":", -1, vbBinaryCompare)
x = LBound(vFilterRange, 1)
y = UBound(vFilterRange, 1)
MsgBox "Lower bound is: " & x & vbCr & "Upper bound is: " & y
End Sub
--
Jim Cone
Portland, Oregon USA
http://www.mediafire.com/PrimitiveSoftware
.
.
.
"RB Smissaert" <bart.sm...@gmail.com>
wrote in message
news:i48n94$b5i$1...@news.eternal-september.org...
As you say, interesting, but not usable.
Peculiar that there is no better way to get the filtered
data other than copying to another sheet.
RBS
"Jim Cone" <james....@comcast.netXXX> wrote in message
news:i4a5h3$iu8$1...@speranza.aioe.org...
This may be better (depending on the definition of better <vbg>).
--
Dave Peterson
RBS
"Dave Peterson" <pete...@XSPAMverizon.net> wrote in message
news:i4b766$232$2...@news.eternal-september.org...
--
Dave Peterson
Think I agree with Dave, with a small range it would be faster.
OTH, you'd save some time if you use a permanent dummy sheet in an addin,
rather than creating/deleting a sheet each time.
Regards,
Peter T
"RB Smissaert" <bart.sm...@gmail.com> wrote in message
news:i4b7uj$cln$1...@news.eternal-september.org...
RBS
"Peter T" <pet...@discussions.com> wrote in message
news:i4bea4$ja8$1...@news.eternal-september.org...
Function getFilteredRows2(rngFilter As Range, _
Optional bOmitHeader As Boolean) As Variant
Dim r As Long
Dim n As Long
Dim c As Long
Dim x As Long
Dim lFirstRow As Long
Dim arr() As Variant
Dim lRows As Long
Dim lColumns As Long
lRows = rngFilter.Rows.Count
lColumns = rngFilter.Columns.Count
If bOmitHeader Then
lFirstRow = 2
Else
lFirstRow = 1
End If
'count non-hidden rows
'---------------------
For r = lFirstRow To lRows
If rngFilter.Cells(r, 1).EntireRow.Hidden = False Then
n = n + 1
End If
Next r
'size the final array
'--------------------
ReDim arr(1 To n, 1 To lColumns) As Variant
'get the data of the non-hidden rows
'-----------------------------------
If lColumns = 1 Then
For r = lFirstRow To lRows
If rngFilter.Cells(r, 1).EntireRow.Hidden = False Then
x = x + 1
arr(x, 1) = rngFilter.Cells(r, 1)
End If
Next r
Else
For r = lFirstRow To lRows
If rngFilter.Cells(r, 1).EntireRow.Hidden = False Then
x = x + 1
For c = 1 To lColumns
arr(x, c) = rngFilter.Cells(r, c)
Next c
End If
Next r
End If
getFilteredRows2 = arr
End Function
RBS
"RB Smissaert" <bart.sm...@gmail.com> wrote in message
news:i4beqb$dv0$1...@news.eternal-september.org...
Function getFilteredRows3(rngFilter As Range, _
Optional bOmitHeader As Boolean) As Variant
Dim r As Long
Dim n As Long
Dim c As Long
Dim x As Long
Dim lFirstRow As Long
Dim arr() As Variant
Dim lRows As Long
Dim lColumns As Long
lRows = rngFilter.Rows.Count
lColumns = rngFilter.Columns.Count
If bOmitHeader Then
lFirstRow = 2
Else
lFirstRow = 1
End If
'count non-hidden rows
'---------------------
ReDim bArrVis(lFirstRow To lRows) As Boolean
For r = lFirstRow To lRows
If rngFilter.Cells(r, 1).EntireRow.Hidden = False Then
n = n + 1
bArrVis(r) = True
End If
Next r
'size the final array
'--------------------
ReDim arr(1 To n, 1 To lColumns) As Variant
'get the data of the non-hidden rows
'-----------------------------------
If lColumns = 1 Then
For r = lFirstRow To lRows
'If rngFilter.Cells(r, 1).EntireRow.Hidden = False Then
If bArrVis(r) Then
x = x + 1
arr(x, 1) = rngFilter.Cells(r, 1)
End If
Next r
Else
ReDim arrRow(1 To rngFilter.Columns.Count)
For r = lFirstRow To lRows
'If rngFilter.Cells(r, 1).EntireRow.Hidden = False Then
If bArrVis(r) Then
x = x + 1
arrRow = rngFilter.Rows(r).Cells.Value
For c = 1 To lColumns
' arr(x, c) = rngFilter.Cells(r, c)
arr(x, c) = arrRow(1, c)
Next c
End If
Next r
End If
getFilteredRows3 = arr
End Function
Of course the proportion of filtered/hidden rows and number of columns would
be factors either way.
Regards,
Peter T
PS only very lightly tested!
"RB Smissaert" <bart.sm...@gmail.com> wrote in message
news:i4c0d8$6oq$1...@news.eternal-september.org...
RBS
"Peter T" <pet...@discussions.com> wrote in message
news:i4c3gn$flt$1...@news.eternal-september.org...
RBS
"RB Smissaert" <bart.sm...@gmail.com> wrote in message
news:i4c3sa$9bk$1...@news.eternal-september.org...
Function getFilteredRows4(rngFilter As Range, _
Optional bOmitHeader As Boolean) As Variant
Dim r As Long
Dim n As Long
Dim c As Long
Dim x As Long
Dim lFirstRow As Long
Dim arrRange() As Variant
Dim arr() As Variant
Dim arrVisibleRows() As Boolean
Dim lRows As Long
Dim lColumns As Long
lRows = rngFilter.Rows.Count
lColumns = rngFilter.Columns.Count
If bOmitHeader Then
lFirstRow = 2
Else
lFirstRow = 1
End If
'put the range in an array
'-------------------------
arrRange = rngFilter
'setup a boolean array to store non-hidden rows
'----------------------------------------------
ReDim arrVisibleRows(lFirstRow To lRows)
'count non-hidden rows and store in Boolean array
'------------------------------------------------
For r = lFirstRow To lRows
If rngFilter.Cells(r, 1).EntireRow.Hidden = False Then
n = n + 1
arrVisibleRows(r) = True
End If
Next r
'size the final array
'--------------------
ReDim arr(1 To n, 1 To lColumns) As Variant
'get the data of the non-hidden rows
'-----------------------------------
If lColumns = 1 Then
For r = lFirstRow To lRows
If arrVisibleRows(r) Then
x = x + 1
arr(x, 1) = arrRange(r, 1)
End If
Next r
Else
For r = lFirstRow To lRows
If arrVisibleRows(r) Then
x = x + 1
For c = 1 To lColumns
arr(x, c) = arrRange(r, c)
Next c
End If
Next r
End If
getFilteredRows4 = arr
End Function
Can't see much scope now to make this faster.
RBS
"Peter T" <pet...@discussions.com> wrote in message
news:i4c3gn$flt$1...@news.eternal-september.org...
Option Explicit
Sub testme()
Dim VisRng As Range
Dim wks As Worksheet
Dim myArr As Variant
Dim rCtr As Long
Dim cCtr As Long
Dim myCell As Range
Set wks = Worksheets("Sheet1")
With wks
With .AutoFilter.Range
With .Columns(1)
If .Cells.SpecialCells(xlCellTypeVisible).Cells.Count = 1 Then
MsgBox "only headers visible"
Exit Sub 'do nothing
End If
Set VisRng = .Resize(.Rows.Count - 1).Offset(1, 0) _
.Cells.SpecialCells(xlCellTypeVisible)
End With
ReDim myArr(1 To VisRng.Cells.Count, 1 To .Columns.Count)
rCtr = 0
For Each myCell In VisRng.Cells
rCtr = rCtr + 1
For cCtr = 1 To .Columns.Count
myArr(rCtr, cCtr) = myCell.Offset(0, cCtr - 1).Value
Next cCtr
Next myCell
End With
End With
End Sub
I didn't do any comparison to see what is faster.
--
Dave Peterson
FWIW I found the example I posted between 2 to 4 times faster depending on
the test range.
Regards,
Peter T
"RB Smissaert" <bart.sm...@gmail.com> wrote in message
news:i4c5f2$q2e$1...@news.eternal-september.org...
FWIW I find SpecialCells can be extremely slow if trying to create a large
multi-area range.
Regards,
Peter T
"Dave Peterson" <pete...@XSPAMverizon.net> wrote in message
news:i4c691$2m3$1...@news.eternal-september.org...
Bit faster though to read just the whole range into an array.
Never found something 4 times faster, but that may have to do with the data
we are looking at.
RBS
"Peter T" <pet...@discussions.com> wrote in message
news:i4c89h$5dm$1...@news.eternal-september.org...
--
Dave Peterson