Я хочу ускорить процесс. У меня есть таблица, которая выглядит примерно так:
У меня такая структура данных:
+-------------------+
| 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 секунд. Я ищу способ ускорить это, если это возможно.
Я также отключил автокаски, события и т. д.
Да, я неправильно прочитал, извините.
Возможно, создайте составной диапазон с помощью union (), а затем очистите, что однажды это ClearContents дорого.
@AlexK. - Вот о чем я думал. В общем, будет ли быстрее очищаться от союза, проходя через его диапазоны?
Я бы подумал, что код, который меньше взаимодействует с листом, будет быстрее, но это покажет только тестирование.


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 - В первую очередь обновление экрана, отключение событий и изменение расчета на ручной при запуске должны помочь сократить затрачиваемое время.
Я также думаю, что вы могли бы создать объединение всех именованных диапазонов, за исключением того, что я не думаю, что это будет быстрее, чем очистить сразу, чем цикл.
При этом используется словарь, чтобы собрать все именованные диапазоны на соответствующих листах и объединить их в один диапазон, а затем просмотреть эти листы, содержащие именованные диапазоны, и очистить их содержимое. Это должно быть выполнено очень быстро за вас:
РЕДАКТИРОВАТЬ: макрос теперь будет проходить только по именованным диапазонам, которые существуют в указанном списке.
РЕДАКТИРОВАТЬ 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 Правильно, это очистит все именованные диапазоны. Из вашего исходного вопроса: ... "Однако, поскольку у меня есть 35000 или около того, чтобы очистить ...", и вы не указываете, что хотите только несколько избранных. Как определяются те немногие, которые вы хотели бы очистить? У вас есть список названных имен диапазонов? Или, возможно, они ограничены одним листом?
Извините, таблица в моем вопросе - это всего лишь снимок. Я получаю ранжированные имена, которые хочу удалить из этой таблицы, в ней около 35000 записей, поэтому я мог бы получить список именованных диапазонов, например, выполнив range («A1: A35000»).
@ user33484 Хорошо, я вижу, у вас есть конкретный рабочий лист, в котором перечислены все конкретные имена именованных диапазонов, которые вы хотите очистить. Я не понял это буквально. Достаточно легко обновить код, дайте мне минутку.
@ user33484 - у вас есть таблица с более чем 35000 именованными диапазонами ??
@BruceWayne Да.
Просто получите индекс вне допустимого диапазона, запустив его как есть. Не уверен, почему, возможно, поскольку есть объединенные ячейки? попробую отладить
@ user33484 gah, объединенные ячейки хуже всего, всегда старайтесь избегать объединенных ячеек. есть ли конкретная причина, по которой вы используете объединенные ячейки, кроме косметических?
@ user33484 Кроме того, если вы просто запускаете код «как есть», я ожидаю, что вы получите ошибку индекса вне допустимого диапазона. Вам необходимо обновить имя листа и букву столбца для переменных NamedRangeList, чтобы он мог найти ваш список имен именованных диапазонов.
Спасибо, индекс все еще выходит за пределы допустимого диапазона. Я не могу отладить его, поскольку он ссылается на правильное имя диапазона, но каким-то образом возникает эта ошибка. Я обновил по инструкции
@ user33484 Я снова обновил код, попробуйте еще раз, иначе его нужно будет отредактировать.
То же самое, к сожалению, застревает: Set rName = wb.Sheets (sheet) .Range (stRange). Ячейка, о которой идет речь, является объединенной ячейкой, поэтому она выходит за пределы диапазона.
Когда вы нажимаете «Отладка», наведите указатель мыши на sSheet и sRange и убедитесь, что лист существует в вашей книге и диапазон правильный (он может не включать объединенный диапазон ячеек, который будет добавлен чуть позже). Похоже, именованный диапазон относится к листу, который больше не существует, или ячейке (или диапазону ячеек), которая больше не существует, что приводит к ошибке #REF!, которая может вызвать ошибку, которую вы видите. Это происходит при удалении листа или диапазона ячеек, содержащих именованные диапазоны. Я поставлю чек на действительные ссылки
Не думаю, что дело в этом. Я думаю, это потому, что когда вы получаете лист и ячейку, лист заключен в одинарные кавычки. Например. если имя листа было ExampeName, оно вернет 'ExampleName', и это вызовет ошибку
После исправления все заработало, но, к сожалению, скорость такая же! Спасибо за Ваш ответ
@ user33484 А, хорошо, в именах ваших листов есть пробелы. Рад слышать, что у вас это работает. Мне жаль слышать, что это такая же скорость.
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
Нет, очищается Range ("Name1"). Clearcontent, затем Range ("Name2"). Clearcontents и т. д.