简体   繁体   English

在Excel中有效地复制可见/过滤的行

[英]Copying visible/filtered rows efficiently in excel

I am working with some very large datasets (various sheets with 65K+ rows and many columns each). 我正在处理一些非常大的数据集(各具有65K +行和多列的工作表)。 I am trying to write some code to copy filtered data from one sheet to a new empty sheet as fast as possible, but have not had much success so far. 我正在尝试编写一些代码,以将过滤后的数据从一张纸尽可能快地复制到一个新的空纸上,但是到目前为止还没有取得太大的成功。

I can include the rest of the code by request, but all it does is calculates the source and destination ranges (srcRange and destRange). 我可以根据请求包含其余代码,但是它所做的只是计算源和目标范围(srcRange和destRange)。 The time taken to calculate these is negligible. 计算这些时间可以忽略不计。 The vast majority of the time is being spent on this line (4 minutes 50 seconds to be precise): 绝大多数时间都花在了这条线上(准确地说是4分50秒):

srcRange.Rows.SpecialCells(xlCellTypeVisible).Copy Destination:=destRange

Additionally I've tried this: 另外,我已经尝试过了:

destRange.Value = srcRange.Rows.SpecialCells(xlCellTypeVisible).Value

But it doesn't work properly when there's a filter. 但是,当有过滤器时,它将无法正常工作。

Function FastCopy(srcSheet As String, srcCol As String, destSheet As String, destCol As String)

    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual

    Dim srcRange As Range
    Dim destRange As Range

    Set srcRange = GetColumnRangeByHeaderName(srcSheet, srcCol, -1)
    Set destRange = GetColumnRangeByHeaderName(destSheet, destCol, srcRange.Rows.Count)


    'destRange.Value = srcRange.Rows.SpecialCells(xlCellTypeVisible).Value

    srcRange.Rows.SpecialCells(xlCellTypeVisible).Copy Destination:=destRange

    Application.ScreenUpdating = True
    Application.Calculation = xlCalculationManual
End Function

This is a slow, dual core machine with 2GB of RAM running excel 2010. Results will obviously vary on a faster machine. 这是一台速度慢的双核计算机,具有2GB RAM,在excel 2010中运行。在速度更快的计算机上,结果显然会有所不同。

Try something like this to work with filtered ranges. 尝试使用类似方法来处理过滤范围。 You're on the right track, the .Copy method is expensive and simply writing values from range to range should be much faster, however as you observe, this doesn't work when a range is filtered. 您在正确的轨道上, .Copy方法非常昂贵,并且简单地写入范围之间的值应该更快,但是,如您.Copy ,对范围进行过滤时,这是行不通的。 When the range is filtered, you need to iterate the .Areas in the range's .SpecialCells : 过滤范围后,您需要迭代范围.SpecialCells.Areas

Sub Test()
Dim rng As Range
Dim subRng As Range
Dim destRng As Range


Set destRng = Range("A10")

Set rng = Range("A1:B8").SpecialCells(xlCellTypeVisible)

For Each subRng In rng.Areas
    Set destRng = destRng.Resize(subRng.Rows.Count, subRng.Columns.Count)
    destRng.Value = subRng.Value
    Set destRng = destRng.Cells(destRng.Rows.Count, 1).Resize(1, 1).Offset(1, 0)
Next

End Sub

Modified for your purposes, but untested: 根据您的目的进行了修改,但未经测试:

Function FastCopy(srcSheet As String, srcCol As String, destSheet As String, destCol As String)

    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual

    Dim srcRange As Range
    Dim destRange As Range
    Dim subRng As Range

    Set srcRange = GetColumnRangeByHeaderName(srcSheet, srcCol, -1)
    Set destRange = GetColumnRangeByHeaderName(destSheet, destCol, srcRange.Rows.Count)

    For Each subRng In srcRange.Areas
        Set destRng = destRng.Resize(subRng.Rows.Count, subRng.Columns.Count)
        destRng.Value = subRng.Value
        Set destRng = destRng.Cells(destRng.Rows.Count, 1).Resize(1, 1).Offset(1, 0)
    Next

    Application.ScreenUpdating = True
    Application.Calculation = xlCalculationManual
End Function

Simplest copying (no filter) 最简单的复制(无过滤器)

Range("F1:F53639").Value = Range("A1:A53639").Value

To expand on my comment 扩大我的评论

Sub Main()
Application.ScreenUpdating = False
    ' paste the Range into an array
    Dim arr
    arr = Range("$A$1:$A$53639").Value

    ' fill the range based on the array
    Range("$F$1").Resize(UBound(arr, 1), UBound(arr, 2)) = arr


    ' apply the same filter to your copied range as the original range
        '+  i don't know how you have applied your filter but just re-apply it to column F

    ' and delete the invisible cells
    ' unfortunately there is no xlCellTypeHidden or xlCelltypeInvisible hehe so you have to iterate
    Dim i As Long
    For i = Range("F" & Rows.Count).End(xlUp).Row To 1 Step -1
        If (Range("F" & i).EntireRow.Hidden) Then Range("F" & i).Delete
        ' or Range("F" & i).EntireRow.Delete
    Next i
Application.ScreenUpdating = True
End Sub

If you could provide the time it took you to run it that would be great I am very curious 如果您能提供运行它所花费的时间,那太好了,我很好奇


I just ran this code on 53639 rows and it took less than 1 second 我只是在53639行上运行了这段代码,花费了不到1秒的时间

Sub Main()
Application.ScreenUpdating = False

    Dim tNow As Date
    tNow = Now

    ' paste the Range into an array
    Dim arr
    arr = Range("$A$1:$A$53639").Value

    ' fill the range based on the array
    Range("$F$1").Resize(UBound(arr, 1), UBound(arr, 2)) = arr

    ' apply the same filter to your copied range as the original range
    ActiveSheet.Range("$F$1:$F$53640").AutoFilter Field:=1, Criteria1:="a"

    ' and delete the invisible cells
    ' unfortunately there is no xlCellTypeHidden or xlCelltypeInvisible hehe so you have to iterate
    Dim i As Long
    For i = Range("F" & Rows.Count).End(xlUp).Row To 1 Step -1
        If (Range("F" & i).EntireRow.Hidden = True) Then
            Range("F" & i).Delete
        End If
    Next i

    Debug.Print DateDiff("s", tNow, Now)
Application.ScreenUpdating = True
End Sub

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM