VBA - очистить тысячи ячеек одновременно

Я хочу ускорить процесс. У меня есть таблица, которая выглядит примерно так:

У меня такая структура данных:

+-------------------+
| Excel Ranged Name |
+-------------------+
| Name1             |
| Name2             |
| Name3             |
| Name4             |
| Name5             |
| Name6             |
| Name7             |
| Name8             |
| Name9             |
| Name10            |
| Name11            |
+-------------------+

Где Name1, Name2 и т. д. Представляют собой действительные ранжированные имена в электронной таблице. т.е. есть ячейка с именем "Name1" и т. д.

Я хочу создать макрос, который очистит содержимое каждого из названных диапазонов. Я могу сделать это с помощью цикла for:

Sub cleartest()

For i = 1 To 35000
    With Sheets("Sheet1")
        .Range(Cells(i, 1)).ClearContents
    End With
Next i




End Sub

Однако, поскольку у меня около 35000 для очистки, для моего ПК требуется 30-40 секунд. Я ищу способ ускорить это, если это возможно.

Я также отключил автокаски, события и т. д.

Нет, очищается Range ("Name1"). Clearcontent, затем Range ("Name2"). Clearcontents и т. д.

user33484 12.10.2018 15:59

Да, я неправильно прочитал, извините.

BruceWayne 12.10.2018 16:00

Возможно, создайте составной диапазон с помощью union (), а затем очистите, что однажды это ClearContents дорого.

Alex K. 12.10.2018 16:07

@AlexK. - Вот о чем я думал. В общем, будет ли быстрее очищаться от союза, проходя через его диапазоны?

BruceWayne 12.10.2018 16:10

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

Alex K. 12.10.2018 16:12
Преобразование HTML-таблицы в профессиональный документ Excel
Преобразование HTML-таблицы в профессиональный документ Excel
Это самый простой способ создания Excel из HTML-таблицы.
Импорт excel в laravel в базу данных
Импорт excel в laravel в базу данных
Здравствуйте, дорогой читатель, в этой статье я расскажу практическим и быстрым способом, как импортировать файл Excel в вашу базу данных с помощью...
0
5
537
6

Ответы 6

Option Explicit

Sub t()
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual

Dim rng As Range
Set rng = Range("A2:A3") ' this is the range where your named ranges are kept

Dim cel As Range

For Each cel In rng
    Range(cel.Value).ClearContents
Next cel

Application.ScreenUpdating = True
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic

End Sub

Я попробую это сейчас и вернусь к вам. Однако есть объединенные ячейки, как с ними бороться? Могу я спросить, как это будет быстрее, если это тот же цикл? Ваше здоровье

user33484 12.10.2018 16:05

@ user33484 - В первую очередь обновление экрана, отключение событий и изменение расчета на ручной при запуске должны помочь сократить затрачиваемое время.

BruceWayne 12.10.2018 16:06

Я также думаю, что вы могли бы создать объединение всех именованных диапазонов, за исключением того, что я не думаю, что это будет быстрее, чем очистить сразу, чем цикл.

BruceWayne 12.10.2018 16:09

При этом используется словарь, чтобы собрать все именованные диапазоны на соответствующих листах и ​​объединить их в один диапазон, а затем просмотреть эти листы, содержащие именованные диапазоны, и очистить их содержимое. Это должно быть выполнено очень быстро за вас:

РЕДАКТИРОВАТЬ: макрос теперь будет проходить только по именованным диапазонам, которые существуют в указанном списке.

РЕДАКТИРОВАТЬ 2: теперь макрос будет учитывать именованные диапазоны, в которых есть объединенные ячейки.

РЕДАКТИРОВАТЬ 3: макрос теперь будет учитывать именованные диапазоны, которые имеют несколько областей несмежных областей диапазона, где одна или несколько из этих областей являются объединенной ячейкой.

РЕДАКТИРОВАТЬ 4: макрос теперь учитывает возможные ошибки #REF из устаревших именованных диапазонов.

РЕДАКТИРОВАТЬ 5: макрос теперь учитывает листы с пробелами в их именах.

Sub tgr()

    Dim wb As Workbook
    Dim wsNamedRangeList As Worksheet
    Dim rNamedRangeList As Range
    Dim rName As Range
    Dim rTest As Range
    Dim aAreas As Variant
    Dim vArea As Variant
    Dim vName As Variant
    Dim vSheetNamesRange As Variant
    Dim hSheets As Object
    Dim sSheet As String
    Dim sRange As String

    Set wb = ActiveWorkbook
    Set wsNamedRangeList = wb.Sheets("NamedRangeList")  'Change this to the actual name of the worksheet containing the list of named range names
    Set rNamedRangeList = wsNamedRangeList.Columns("A") 'Change this to the actual column containing the list of named range names
    Set hSheets = CreateObject("Scripting.Dictionary")

    For Each vName In wb.Names
        Set rTest = rNamedRangeList.Find(vName.Name, , xlValues, xlWhole, , , False)
        If Not rTest Is Nothing Then
            aAreas = Split(vName, ",")
            For Each vArea In aAreas
                sSheet = Split(vArea, "!")(0)
                If Left(sSheet, 1) = " = " Then sSheet = Mid(sSheet, 2)
                If Left(sSheet, 1) = "'" Then sSheet = Mid(sSheet, 2, Len(sSheet) - 2)
                sRange = Split(vArea, "!")(1)
                If sSheet <> "#REF" And sRange <> "#REF" Then
                    Set rName = wb.Sheets(sSheet).Range(sRange)
                    If hSheets.Exists(sSheet) Then
                        Set hSheets(sSheet) = Union(hSheets(sSheet), rName.MergeArea)
                    Else
                        Set hSheets(sSheet) = rName.MergeArea
                    End If
                End If
            Next vArea
        End If
    Next vName

    For Each vSheetNamesRange In hSheets.Items
        vSheetNamesRange.ClearContents
    Next vSheetNamesRange

End Sub

Это очищает все ранжированные имена, нет? Я просто хочу несколько избранных

user33484 12.10.2018 16:16

@ user33484 Правильно, это очистит все именованные диапазоны. Из вашего исходного вопроса: ... "Однако, поскольку у меня есть 35000 или около того, чтобы очистить ...", и вы не указываете, что хотите только несколько избранных. Как определяются те немногие, которые вы хотели бы очистить? У вас есть список названных имен диапазонов? Или, возможно, они ограничены одним листом?

tigeravatar 12.10.2018 16:18

Извините, таблица в моем вопросе - это всего лишь снимок. Я получаю ранжированные имена, которые хочу удалить из этой таблицы, в ней около 35000 записей, поэтому я мог бы получить список именованных диапазонов, например, выполнив range («A1: A35000»).

user33484 12.10.2018 16:19

@ user33484 Хорошо, я вижу, у вас есть конкретный рабочий лист, в котором перечислены все конкретные имена именованных диапазонов, которые вы хотите очистить. Я не понял это буквально. Достаточно легко обновить код, дайте мне минутку.

tigeravatar 12.10.2018 16:20

@ user33484 - у вас есть таблица с более чем 35000 именованными диапазонами ??

BruceWayne 12.10.2018 16:20

@BruceWayne Да.

user33484 12.10.2018 16:20

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

user33484 12.10.2018 16:32

@ user33484 gah, объединенные ячейки хуже всего, всегда старайтесь избегать объединенных ячеек. есть ли конкретная причина, по которой вы используете объединенные ячейки, кроме косметических?

tigeravatar 12.10.2018 16:33

@ user33484 Кроме того, если вы просто запускаете код «как есть», я ожидаю, что вы получите ошибку индекса вне допустимого диапазона. Вам необходимо обновить имя листа и букву столбца для переменных NamedRangeList, чтобы он мог найти ваш список имен именованных диапазонов.

tigeravatar 12.10.2018 16:38

Спасибо, индекс все еще выходит за пределы допустимого диапазона. Я не могу отладить его, поскольку он ссылается на правильное имя диапазона, но каким-то образом возникает эта ошибка. Я обновил по инструкции

user33484 12.10.2018 16:42

@ user33484 Я снова обновил код, попробуйте еще раз, иначе его нужно будет отредактировать.

tigeravatar 12.10.2018 16:44

То же самое, к сожалению, застревает: Set rName = wb.Sheets (sheet) .Range (stRange). Ячейка, о которой идет речь, является объединенной ячейкой, поэтому она выходит за пределы диапазона.

user33484 12.10.2018 16:46

Когда вы нажимаете «Отладка», наведите указатель мыши на sSheet и sRange и убедитесь, что лист существует в вашей книге и диапазон правильный (он может не включать объединенный диапазон ячеек, который будет добавлен чуть позже). Похоже, именованный диапазон относится к листу, который больше не существует, или ячейке (или диапазону ячеек), которая больше не существует, что приводит к ошибке #REF!, которая может вызвать ошибку, которую вы видите. Это происходит при удалении листа или диапазона ячеек, содержащих именованные диапазоны. Я поставлю чек на действительные ссылки

tigeravatar 12.10.2018 16:59

Не думаю, что дело в этом. Я думаю, это потому, что когда вы получаете лист и ячейку, лист заключен в одинарные кавычки. Например. если имя листа было ExampeName, оно вернет 'ExampleName', и это вызовет ошибку

user33484 12.10.2018 17:07

После исправления все заработало, но, к сожалению, скорость такая же! Спасибо за Ваш ответ

user33484 12.10.2018 17:14

@ user33484 А, хорошо, в именах ваших листов есть пробелы. Рад слышать, что у вас это работает. Мне жаль слышать, что это такая же скорость.

tigeravatar 12.10.2018 17:15
Option Explicit

Sub t()
On Error GoTo exitErr
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual

Dim rng As Range
Set rng = Range("A2:A3") ' this is the range where your named ranges are kept

Dim nmRng As Range, cel As Range

For Each cel In rng
    Range(cel.Value).ClearContents
Next cel

ExitErr:
   Application.ScreenUpdating = True
   Application.EnableEvents = True
   Application.Calculation = xlCalculationAutomatic

End Sub

@BruceWayne - ПОЖАЛУЙСТА, обработка ошибок. Почему это так важно?? Что произойдет, если один из диапазонов в списке отсутствует? Ваш код ломается, обновление экрана прекращается, события не запускаются, и ваши формулы перестают вычисляться, так как они были выключены и больше никогда не включаются.

Вызов ClearNamedRanges с диапазоном имен, который вы хотите очистить

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

Обновлено: я считаю, что Application.Match может работать быстрее, чем Range.Find Test, оба дайте мне знать.

Sub Test()
    Call ClearNamedRanges(Sheet1.Range("A1:A35000"))
End Sub

Private Sub ClearNamedRanges(ByRef oNameRange As Range)

    Dim oName As Name
    For Each oName In ActiveWorkbook.Names
        'if Not IsError(Application.Match(oName.Name, oNameRange, 0)) Then oName.RefersToRange.ClearContents
        If Not oNameRange.Find(oName.Name) Is Nothing Then oName.RefersToRange.ClearContents
    Next
End Sub

Мне любопытно посмотреть, будет ли это вообще быстрее. Вместо того, чтобы обращаться к листу дважды, .Range и Cells, я просматриваю массив так, чтобы в цикле была только одна ссылка на лист.

Sub cleartest()

    Dim RangeNames() as Variant

    RangeNames = Worksheets("Sheet1").Range("A1:A35000").value
    For i = 1 To 35000
        With Sheets("Sheet1")
            .Range(RangeNames(i,1)).ClearContents
        End With
    Next i

End Sub

Что-то еще, что можно попробовать, может быть использование .Range(RangeNames(i,1)).Value = vbNullString, если вы просто хотите очистить значения. Я не думаю, что это очистит форматирование.

вы можете попробовать управлять только непустыми «объектами» (ячейками с именованным именем диапазона и самими именованными диапазонами)

Sub clear()
    Dim namedRangeCells As Range, cell As Range

    With Sheets("Sheet1") ' reference your sheet
        Set namedRangeCells = .Cells(1, 1) ' set namedRangeCells to a cell you don't care about
        For Each cell In .Range("A1", .Cells(.Rows.Count, 1).End(xlUp)).SpecialCells(xlCellTypeConstants) ' loop thropugh referenced sheet column A not empty cells
            Set namedRangeCells = Union(namedRangeCells, .Range(cell.Value)) ' collect named ranges
        Next
    End With

    namedRangeCells.SpecialCells(xlCellTypeConstants).ClearContents ' clear collected named ranges with with not empty value
End Sub

Другие вопросы по теме