Удаление 15000 пустых строк из данных, но код чрезвычайно медленный

#excel #vba

Вопрос:

Разработанный ниже код для удаления количества строк, если он пустой, работает нормально, но для обработки требуется много времени.

Это должно быть быстрее. Я надеюсь получить некоторую помощь. Спасибо

 Sub DeleteEmptyRows()
    Dim ws As Worksheet
    Dim rng As Range
    Dim lastRow As Long

    Set ws = Sheet1

    lastRow = ws.Range("Y" amp; ws.Rows.Count).End(xlUp).Row

    Set rng = ws.Range("Y2:Y" amp; lastRow)

    With rng
        .AutoFilter Field:=1, Criteria1:="="
        .Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
    End With

    ws.AutoFilterMode = False
End Sub 
 

Комментарии:

1. Попробуйте ClearContents перед удалением. Это может не сильно помочь, но это ускорит процесс.

2. Попытался очистить содержимое, но для удаления строк требуется столько же времени

3. Начните с последней строки и работайте вверх — в противном случае excel должен перемещать все остальные строки вверх каждый раз, когда он удаляет одну из них.

4. Существуют ли какие-либо формулы, форматы, условное форматирование, на которые повлияет удаление строк?

5. Не могли бы вы поделиться решением, как вы предложили @Solar Mike

Ответ №1:

Удалите Несоответствующие Строки

  • Это не приведет к удалению каких-либо строк, а только к перезаписи. Это будет работать только в том случае, если ваши данные являются значениями, потому что любые формулы будут перезаписаны значениями.
  • Для простоты данные должны быть непрерывными и начинаться с ячейки A1 ( CurrentRegion ).
  • Оба решения делают одно и то же. В выборке из 100 тысяч строк с 33 тысячами совпадений первое заняло 3 секунды, в то время как второе заняло 5 секунд ( Application.Match довольно медленно применяется к массиву).
  • Вы серьезно изменили свой вопрос. Чтобы второе решение работало для текущего вопроса (удалить пустые строки), вы можете избавиться от 3 строк, содержащих Criteria и использовать:
     If Len(CStr(Data(r, Col))) > 0 Then
     

Код

 Option Explicit

Sub DeleteRows()
    
    Const FirstRow As Long = 2
    Const Col As Long = 25
    Const CriteriaList As String = "Trans,Hub" ' *** If you add here...
    
    ' Create a reference to the Source Data Range ('srg') (no headers).
    Dim ws As Worksheet: Set ws = Sheet1
    Dim rg As Range: Set rg = ws.Range("A1").CurrentRegion
    Dim rCount As Long: rCount = rg.Rows.Count
    If rCount = 1 Then Exit Sub ' no data rows
    Dim srCount As Long: srCount = rCount - 1
    Dim cCount As Long: cCount = rg.Columns.Count
    Dim srg As Range: Set srg = rg.Resize(srCount).Offset(1)
    Debug.Print srg.Address
    
    ' Write the values from the Source Range to a 2D one-based array ('Data').
    Dim Data As Variant: Data = srg.Value
    
    ' Write the 'matching' values to the top of the array.
    Dim Criteria() As String: Criteria = Split(CriteriaList, ",")
    ' *** ... you also have to add here...
    Dim Crit1 As String: Crit1 = UCase(Criteria(0))
    Dim Crit2 As String: Crit2 = UCase(Criteria(1))
    ' *** ... meaning here...
    
    Dim r As Long ' Rows Counter
    Dim c As Long ' Columns Counter
    Dim n As Long ' Matching Rows Counter
    For r = 1 To srCount
        Select Case UCase(CStr(Data(r, Col)))
        Case Crit1, Crit2 ' *** ... and here.
            n = n   1
            For c = 1 To cCount
                Data(n, c) = Data(r, c)
            Next c
        End Select
    Next r
    If n = srCount Then Exit Sub ' all matches
    
    ' Write the matching values ('n') from the array to the Destination Range.
    Dim drg As Range: Set drg = srg.Resize(n, cCount)
    Debug.Print drg.Address
    drg.Value = Data
    
    ' Clear contents of the Clear Range,
    ' i.e. the range below the Destination Range.
    Dim crg As Range: Set crg = srg.Resize(srCount - n).Offset(n)
    Debug.Print crg.Address
    crg.ClearContents

End Sub

Sub DeleteRowsApplicationMatch()
    
    Const FirstRow As Long = 2
    Const Col As Long = 25
    Const CriteriaList As String = "Trans,Hub"
    
    ' Create a reference to the Source Data Range ('srg') (no headers).
    Dim ws As Worksheet: Set ws = Sheet1
    Dim rg As Range: Set rg = ws.Range("A1").CurrentRegion
    Dim rCount As Long: rCount = rg.Rows.Count
    If rCount = 1 Then Exit Sub ' no data rows
    Dim srCount As Long: srCount = rCount - 1
    Dim cCount As Long: cCount = rg.Columns.Count
    Dim srg As Range: Set srg = rg.Resize(srCount).Offset(1)
    Debug.Print srg.Address
    
    ' Write the values from the Source Range to a 2D one-based array ('Data').
    Dim Data As Variant: Data = srg.Value
    
    ' Write the 'matching' values to the top of the array.
    Dim Criteria() As String: Criteria = Split(CriteriaList, ",")
    Dim r As Long ' Rows Counter
    Dim c As Long ' Columns Counter
    Dim n As Long ' Matching Rows Counter
    For r = 1 To srCount
        If IsNumeric(Application.Match(CStr(Data(r, Col)), Criteria, 0)) Then
            n = n   1
            For c = 1 To cCount
                Data(n, c) = Data(r, c)
            Next c
        End If
    Next r
    If n = srCount Then Exit Sub ' all matches
    
    ' Write the matching values ('n') from the array to the Destination Range.
    Dim drg As Range: Set drg = srg.Resize(n, cCount)
    Debug.Print drg.Address
    drg.Value = Data
    
    ' Clear contents of the Clear Range,
    ' i.e. the range below the Destination Range.
    Dim crg As Range: Set crg = srg.Resize(srCount - n).Offset(n)
    Debug.Print crg.Address
    crg.ClearContents

End Sub
 

Комментарии:

1. Это работает сверх ожиданий, большое вам спасибо @VBasic2008, но это работает для первых критериев, то есть Trans это работает для первого значения до , того Trans , как оно будет работать или Hub не будет работать для значения после ,

2. Убедитесь, что CriteriaList в нем нет пробелов: "Trans,Hub" нет "Trans, Hub" . Код написан для целых слов в ячейках. Если Trans или Hub являются только частями содержимого соответствующих ячеек, оно должно быть изменено.

3. Да, там было место, еще раз спасибо вам за эту великую услугу

Ответ №2:

Удаление 15000 строк в Excel/VBA происходит очень медленно.

Вместо того, чтобы обращаться к каждой отдельной строке по отдельности, попробуйте создать пустой массив, чтобы удалить все данные.

 Dim yourArray As Variant
ReDim yourArray(1 To 15000, 1 To 2)

For k = 0 To 15000
    yourArray(1   k, 1) = ""
    yourArray(1   k, 2) = ""
    ' array(row, column)
Next k

' ...

ws.Range(ws.Cells(1, 1), ws.Cells(15000, 2)) = yourArray
 

Имейте в виду, что это все равно займет несколько секунд и не будет сделано в одно мгновение, как вы могли бы надеяться. Excel и VBA просто не так быстры.

Комментарии:

1. Спасибо за решение, но я не могу его изменить @Lynx

2. Это приведет к удалению (очистке) всех данных, но я хочу просто удалить отфильтрованные строки

3. Ах да, я вижу свою ошибку. С моим решением строки будут очищены, но все еще будут существовать как пустые записи. В этом случае я должен признать, что не знаю более быстрого способа VBA, чем обычный «. Удалить», что, по общему признанию, занимает «»некоторое»» время. Может быть, их быстрее очистить перед удалением?

Ответ №3:

Попробуйте сначала выбрать, а затем удалить выделенное:

 Sub DeleteEmptyRows()
    Dim ws As Worksheet
    Dim rng As Range
    Dim lastRow As Long

    Set ws = Sheet1

    lastRow = ws.Range("Y" amp; ws.Rows.Count).End(xlUp).Row

    Set rng = ws.Range("Y2:Y" amp; lastRow)

    With rng
        .AutoFilter Field:=1, Criteria1:="="
        .Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Select
        Selection.Delete Shift:=xlUp
    End With

    ws.AutoFilterMode = False
End Sub 
 

Комментарии:

1. Спасибо, но это все еще медленно.