Удаление строк (работает в обратном направлении), но использовать переменную диапазона? - PullRequest
0 голосов
/ 01 ноября 2018

Часто требуется, чтобы вы прошли через ряд ячеек и по некоторым критериям удалили всю строку.

На практике лучше всего начинать с конца диапазона и продолжать работу.

Dim i as Long
For i = lastRow to 1 Step -1
    If Cells(i, 2).Value = "del" then Rows(i).EntireRow.Delete
End if

Однако большую часть времени я работаю с Range объектом.

Есть ли способ работать в обратном направлении с объектом диапазона, который не требует использования цикла типа For i?

Dim rng as Range, cel as Range
Set rng = Range("A1:A100")

For each cel in rng step -1
   if cel.value = "del" then cel.EntireRow.Delete
next cel

Это ошибки Expected: End of Statement в части Step -1, что я и ожидал (без каламбура).

Идея состоит в том, что мне не нужно перестраивать свои данные в Cells() при попытке вернуться назад к переменной Range. Я нахожу немного унылым использовать переменные диапазона кучу, но когда нужно удалить строки из этого диапазона, нужно переключиться на использование Cells([long],[long]), если это имеет смысл.

Редактировать: Просто придумал это, но он все еще чувствует себя глупо:

Dim k As Long, cel as Range
Set cel = rng.cells(rng.cells.count)
For k = cel.Row To rng.Cells(1).Row Step -1
    If rng.Cells(k).Value = "del" Then rng.Cells(k).EntireRow.Delete
Next k

Ответы [ 3 ]

0 голосов
/ 02 ноября 2018

Да, вы можете сделать это без For i = заявления. Просто создайте специальный диапазон, который вы удалите после завершения цикла.

Dim cel As Range, rng As Range
Dim delRng As Range

For Each cel In rng
    If cel.Value = "del" Then
        If delRng Is Nothing Then
            Set delRng = cel
        Else
            Set delRng = Union(delRng, cel)
        End If
    End If
Next cel

If Not delRng Is Nothing Then delRng.EntireRow.Delete

И вам даже не нужно отступать назад.

0 голосов
/ 02 ноября 2018

наоборот

"Есть ли способ работать в обратном направлении с объектом диапазона, который не требует использования цикла типа For i?"

В дополнение к правильному решению @ K-Davis, я демонстрирую, как использовать расширенные возможности фильтрации Application.Index метод. Ожидается только три аргумента:

  • массив 2-мерных полей данных v на основе полного набора данных
  • 1-мерный массив поддерживаемых номеров строк, вызываемый через вспомогательную функцию getAr(v, 1), , где аргумент 1 определяет 1-й столбец
  • (одномерный массив всех столбцов, созданный автоматически с помощью Evaluate)

Вместо удаления строк этот подход использовал весь набор данных (например, A2: C10, пропуская предполагаемую строку заголовка) и записывал обратно в массив отфильтрованный массив данных, снова назначая его rng.

Основная процедура

Sub DelRows()
  Dim rng As Range,  v
  Set rng = ThisWorkbook.Worksheets("Sheet1").Range("A2:C10") ' << change to entire data range
' [1a] create 2-dim data field array (1-based)
  v = rng.Value2
' [1b] filter out rows to be deleted
  v = Application.Transpose(Application.Index(v, getAr(v, 1), Evaluate("row(1:" & rng.Columns.Count & ")")))
' [2] write data field back to resized range
  rng = ""                                  ' clear lines
  rng.Resize(UBound(v), UBound(v, 2)) = v
End Sub

Вспомогательная функция getAr()

Function getAr(v, ByVal colNo&) As Variant()
' Purpose: collect row numbers not to be deleted (criteria no "DEL" in 1st column)
' Note:    called by above procedure DelRows
  Dim ar, i&, n&
  ReDim ar(0 To UBound(v) - 1)
  For i = 1 To UBound(v)
      If UCase$(v(i, colNo)) <> "DEL" Then
         ar(n) = i: n = n + 1
      End If
  Next i
  ReDim Preserve ar(0 To n - 1): getAr = ar
End Function

Связанные ссылки SO

Cf. Вставить новый первый столбец в массив полей данных без циклов или вызовов API

0 голосов
/ 01 ноября 2018

Я знаю, вы сказали, что вам не нравится For i, но ИМХО, это самый чистый путь

For i = rng.Rows.Count To 1 Step -1
    With rng.Cells(i, 2)
        If .Value = "del" then
            .Entirerow.Delete
        End If
    End With
Next

Обратите внимание, что конструкция rng.Cells относится к rng

Например, если rng - A100: A1000, то rng.Cells(rng.Rows.Count, 1) относится к A1000

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