Можно ли использовать код VBA на уже отфильтрованном листе? - PullRequest
0 голосов
/ 01 февраля 2020

У меня есть лист с около 6000 строк. В моем коде я сначала отфильтровал несколько строк.

Sheets("privata").Rows("2:" & Rows.count).AutoFilter Field:=26, Criteria1:=">=2020-01-30  09:00:00", Operator:=xlAnd, Criteria2:="<=2020-01-30  09:30:00"
Sheets("privata").Rows("2:" & Rows.count).AutoFilter Field:=24, Criteria1:="<>OK"
Sheets("privata").Rows("2:" & Rows.count).AutoFilter Field:=25, Criteria1:="<>SUPPLY_CONTROL,"

Теперь его число составляет около 350 строк. После того, как я отфильтровал его, я копирую и вставляю данные на другой лист

Sheets("privata").UsedRange.Copy
Sheets("toptre").Range("A1").PasteSpecial xlPasteAll

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

Весь код требует времени для запуска. Пройдя по коду, я обнаружил, что процесс фильтрации очень быстрый. Что требует времени, это вставка данных на другой лист.

Есть ли возможность работы с оригинальным отфильтрованным листом? Когда я пытаюсь это сделать, он использует все 6000 строк, а не только отфильтрованные.

Пример того, что я хочу сделать:

For i = 2 To RowCount + 1
employee = Sheets("privata").Cells(i, 25)
onList = False
    For j = 1 To UBound(employeeList)

            If employee = employeeList(j) Then
                onList = True
                Exit For
            End If
    Next j
If onList = False Then
countEmployees = countEmployees + 1
employeeList(countEmployees) = employee
End If
If onList = True Then
onList = False
End If
Next i

При обращении к ячейкам (2, 25) Я хочу сослаться на второй ряд на отфильтрованном листе. Это может быть строка 3568 на листе. Это возможно?

/ Jens

Ответы [ 2 ]

1 голос
/ 01 февраля 2020

После применения фильтрации вы можете сделать процесс копирования / вставки очень быстрым, если вы не используете al oop, а используете Selection. Например:

Sub TryThis()
    Dim r As Range
    Sheets("privata").Select
    Set r = ActiveSheet.AutoFilter.Range
    r.Select
    Selection.Copy Sheets("toptre").Range("A1")
End Sub

Обычно вы хотите избежать Selection в VBA. Однако в итоге вы получите:

  • блок данных на листе "toptre"
  • блок будет содержать строку заголовка и все видимые строки
  • блок будет просто блоком (без фильтра)
0 голосов
/ 01 февраля 2020

Я не уверен, что это ускорит ваш процесс, но он пытается выполнить sh то, о чем вы спрашиваете в своем вопросе:

Вы можете использовать выражение, предложенное в комментарии @GSerg чтобы создать объект диапазона с только видимыми строками в таблице данных, например,

Dim filteredRange As Range
Set filteredRange = Sheets("privata").UsedRange.Rows.SpecialCells(xlCellTypeVisible)

Предполагая, что на листе есть хотя бы 1 видимая строка (это означает, что приведенный выше оператор не выдаст ошибку), вы затем можно использовать следующую функцию для доступа к этому диапазону, как если бы он был одним непрерывным диапазоном:

Function RelativeCell(rng As Range, ByVal row As Long, ByVal col As Long) As Range
    Dim areaNum As Long: areaNum = 0
    Dim maxRow As Long: maxRow = 0

    Dim areaCount As Long: areaCount = rng.Areas.Count
    Do While maxRow < row
        areaNum = areaNum + 1
        If areaNum > areaCount Then
            Set RelativeCell = Nothing
            Exit Function
        End If

        maxRow = maxRow + rng.Areas(areaNum).Rows.Count
    Loop

    Dim lastArea As Range: Set lastArea = rng.Areas(areaNum)
    Set RelativeCell = lastArea.Cells(row - (maxRow - lastArea.Rows.Count), col)
End Function

Чтобы напечатать все отфильтрованные значения в столбце B, например, вы можете использовать вышеуказанный метод на filteredRange объект (установленный ранее) следующим образом:

    Dim r As Long: r = 1
    Do
        Dim cell As Range: Set cell = RelativeCell(filteredRange, r, 2)
        If cell Is Nothing Then Exit Do

        Debug.Print cell.Value
        r = r + 1
    Loop

Чтобы упростить приведенный выше код, вы также можете использовать функцию для определения последнего относительного номера строки в отфильтрованном диапазоне, используя следующую функцию:

Function RelativeCellLastRow(rng As Range) As Long
    Dim r As Long: r = 0

    Dim i As Long
    For i = 1 To rng.Areas.Count
        r = r + rng.Areas(i).Rows.Count
    Next

    RelativeCellLastRow = r
End Function

Тогда код для печати всех отфильтрованных значений в столбце B будет приведен к следующему:

    Dim r As Long
    For r = 1 To RelativeCellLastRow(filteredRange)
        Debug.Print RelativeCell(testRng, r, 2).Value
    Next

Если вы используете RelativeCellLastRow, было бы хорошо убедитесь, что он выполняется только один раз, чтобы избежать ненужных пересчетов. В приведенном выше For l oop он выполняется только один раз, поскольку VBA выполняет только ограничения For l oop до первой итерации. Если вам нужно это значение несколько раз, вы можете сохранить его в переменной и использовать вместо него.

Идея функции RelativeCell состоит в том, что диапазон, возвращаемый при вызове SpecialCells, является мульти диапазон, то есть диапазон, составленный из нескольких несмежных диапазонов. relativeCell пропускает несмежные области, пока не найдет номер строки, которую ищет. Если номер строки превышает общее количество строк в диапазоне, функция возвращает Nothing, поэтому вызывающий код должен знать об этом, чтобы избежать вызова метода или свойства для Nothing.

It. Также ничего не стоит, что RelativeCell работает в диапазоне со скрытыми строками, а не со скрытыми столбцами. Со скрытыми столбцами код становится немного сложнее, но сложность может быть заключена в функцию RelativeCell, не затрагивая код, использующий функцию.

Опять же, я не уверен, сделает ли это код быстрее. Когда я провел несколько тестов для эмуляции вашего сценария, используя лист с 6000+ строками и 30 столбцами случайных строк, копирование / вставка после фильтрации выполнялась очень быстро, но это могло быть связано с используемой машиной, версией Excel. что я использую (2016), или данные, которые я использовал. Сказав это, я надеюсь, что приведенный выше код поможет вам.

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