Excel это не сложно
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
19.04.2024, 22:07:09

Войти
На форуме добавлена возможность подписки на RSS-ленты любого раздела форума. Подписаться можно, нажав на иконку RSS , расположенную левее наименования раздела.
33 242 Сообщений в 5 457 Тем от 6 758 Пользователей
Последний пользователь: Сергей2662
*
Перейти на сайт Хитрости Надстройка MulTEx Обучающие тренинги Наша группа ВКонтакте
Правила форума Начало Помощь Поиск Календарь Войти Регистрация Выйти
+  Excel это не сложно
|-+  Основные форумы
| |-+  Вопросы по Excel и VBA
| | |-+  Оптимизация быстродействия макроса по удалению строк
Страниц: 1 2 [Все]   Вниз
Печать
Автор Тема: Оптимизация быстродействия макроса по удалению строк  (Прочитано 10105 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Mkdir
Гость
« : 28.06.2018, 09:22:36 »

Добрый день.
Есть макрос на удаление строк выделенных жёлтым
Проблема в том, что таких строк может быть очень много около 25 тысяч это итоговая по документам и макрос работает долго если вообще не зависает.

Вот пример
Код: (vb)
Sub d_rows()
Dim i As Long
If (Range("type").Value <> 5) Then
    For i = ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row To 1 Step -1
        If Cells(i, 1).Interior.ColorIndex = 6 Then Rows(i).Delete
    Next
    
End If
End Sub
« Последнее редактирование: 28.06.2018, 22:17:38 от vikttur » Записан
boa
Старожил
****

Репутация: +22/-0
Офлайн Офлайн

Сообщений: 252


Доброта спасет мир...


Просмотр профиля WWW
« Ответ #1 : 28.06.2018, 10:20:32 »

нарушение правил форума п.4.25.
Исправьте и продолжим
Записан

Ничто не обходится нам так дешево и не ценится так дорого, как вежливость...  Мигель Сервантес де Сааведра

Mkdir
Гость
« Ответ #2 : 28.06.2018, 11:22:46 »

Не нашёл где редактировать можно.
Вот пример

Код: (vb)
Sub d_rows()
Dim i As Long
If (Range("type").Value <> 5) Then
    For i = ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row To 1 Step -1
        If Cells(i, 1).Interior.ColorIndex = 6 Then Rows(i).Delete
    Next
   
End If
End Sub
Записан
vikttur
Глобальный модератор
Ветеран
*****

Репутация: +124/-0
Офлайн Офлайн

Сообщений: 1 816



Просмотр профиля
« Ответ #3 : 28.06.2018, 11:36:34 »

Предложите адекватное название темы
Записан
Mkdir
Гость
« Ответ #4 : 28.06.2018, 12:08:53 »

Предложите адекватное название темы
Готово
Записан
Юрий М
Глобальный модератор
Ветеран
*****

Репутация: +112/-0
Офлайн Офлайн

Сообщений: 2 077



Просмотр профиля E-mail
« Ответ #5 : 28.06.2018, 13:50:01 »

Что готово?
Записан
boa
Старожил
****

Репутация: +22/-0
Офлайн Офлайн

Сообщений: 252


Доброта спасет мир...


Просмотр профиля WWW
« Ответ #6 : 28.06.2018, 20:18:39 »

Всегда, на всех флрумах, оформляйте код спец.тэгами
вот правка к коду которая заставит его работать быстрее
Код: (vb)
Sub d_rows()
    Dim i As Integer, LastRow As Integer
    If (Range("type").Value <> 5) Then
        With Application: .ScreenUpdating = False: .EnableEvents = False
        LastRow = ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row
        For i = LastRow To 1 Step -1
            If Cells(i, 1).Interior.ColorIndex = 6 Then Rows(i).Delete
        Next
        .ScreenUpdating = True: .EnableEvents = True: End With
    End If
End Sub
« Последнее редактирование: 28.06.2018, 20:21:37 от boa » Записан

Ничто не обходится нам так дешево и не ценится так дорого, как вежливость...  Мигель Сервантес де Сааведра

Дмитрий Щербаков(The_Prist)
Администратор
Ветеран
*****

Репутация: +485/-0
Офлайн Офлайн

Сообщений: 5 831



Просмотр профиля WWW
« Ответ #7 : 29.06.2018, 10:28:18 »

Dim i As Integer
Ой-ой-ой! плохая практика при работе со строками использовать тип Integer, т.к. у него макс.значение 32767, а строк на листе минимум 65536. Можно запросто получить ошибку переполнения типа.
Записан

Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
Пункты приёма Спасибов:    -41001332272872  -R298726502453
boa
Старожил
****

Репутация: +22/-0
Офлайн Офлайн

Сообщений: 252


Доброта спасет мир...


Просмотр профиля WWW
« Ответ #8 : 29.06.2018, 10:32:16 »

Да, чё-то я протупил,
а ведь стоял же лонг...
« Последнее редактирование: 30.06.2018, 00:01:38 от vikttur » Записан

Ничто не обходится нам так дешево и не ценится так дорого, как вежливость...  Мигель Сервантес де Сааведра

Юрий М
Глобальный модератор
Ветеран
*****

Репутация: +112/-0
Офлайн Офлайн

Сообщений: 2 077



Просмотр профиля E-mail
« Ответ #9 : 29.06.2018, 10:36:18 »

Отключение обновление экрана даст прирост в скорости, но не радикальный. А вот если удалять не по одной строке, а сразу весь диапазон строк, подлежащих удалению,- почувствуется сразу Улыбка
Записан
boa
Старожил
****

Репутация: +22/-0
Офлайн Офлайн

Сообщений: 252


Доброта спасет мир...


Просмотр профиля WWW
« Ответ #10 : 29.06.2018, 10:48:30 »

Юрий,
предложите вариант кода для сравнения
Записан

Ничто не обходится нам так дешево и не ценится так дорого, как вежливость...  Мигель Сервантес де Сааведра

Юрий М
Глобальный модератор
Ветеран
*****

Репутация: +112/-0
Офлайн Офлайн

Сообщений: 2 077



Просмотр профиля E-mail
« Ответ #11 : 29.06.2018, 11:02:20 »

Проверить не на чем, но при больших объёмах будет очень заметно.
Код: (vb)
Sub УдалениеСтрокОднимМахом()
Dim i As Long, LastRow As Long, DelRa As Range
    LastRow = Cells(Rows.Count, 1).End(xlUp).Row
    Application.ScreenUpdating = False
    For i = 1 To LastRow
        If Cells(i, 1).Interior.ColorIndex = 6 Then
            If DelRa Is Nothing Then
                Set DelRa = Cells(i, 1)
            Else
                Set DelRa = Union(DelRa, Cells(i, 1))
            End If
        End If
    Next
    If Not DelRa Is Nothing Then DelRa.EntireRow.Delete
    Application.ScreenUpdating = True
End Sub
Записан
Дмитрий Щербаков(The_Prist)
Администратор
Ветеран
*****

Репутация: +485/-0
Офлайн Офлайн

Сообщений: 5 831



Просмотр профиля WWW
« Ответ #12 : 29.06.2018, 13:26:09 »

На самом деле все давно придумано и описано: Как удалить строки по условию?
Записан

Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
Пункты приёма Спасибов:    -41001332272872  -R298726502453
boa
Старожил
****

Репутация: +22/-0
Офлайн Офлайн

Сообщений: 252


Доброта спасет мир...


Просмотр профиля WWW
« Ответ #13 : 29.06.2018, 23:50:48 »

Люблю проверять различные утверждения типа "все придумано"

для данного упражнения написал макросики для тестирования.
чуток подкорректировал макрос Юрия(d_rows_2), дабы Юнион уменьшить
и Юрия макрос тоже сохранил Подмигивающий
он, кстати аналогичен варианту из "все придумано"
Желающие могут скачать файл из вложения и потестить самостоятельно...
так вот тесты не утешительные!
оказывается на большом объеме данных последовательное удаление - самое оптимальное

тестировалось на win10, excel2013 x64, i5, 4g оперативы.
результаты в секундах.

d_rows_1  - макрос из моего поста выше;
d_rows_2 - оптимизированный мною макрос Юрия;
УдалениеСтрокОднимМахом - макрос Юрия.



Подготовлено 466 строк для удаления из массива в 1 000 строк.
d_rows_1 - 0,21875
d_rows_2 - 0,1171875
УдалениеСтрокОднимМахом - 0,296875

Подготовлено 4 666 строк для удаления из массива в 10 000 строк.
d_rows_1 - 1,3125
d_rows_2 - 3,023438
УдалениеСтрокОднимМахом - 80,72656
почувствуется сразу
почуствовал...

Подготовлено 46 666 строк для удаления из массива в 100 000 строк.
d_rows_1 - 123,3047, т.е 2 минуты
d_rows_2 - 2623,789   - ~44 минуты
УдалениеСтрокОднимМахом - "залип", может попозже раздуплится, напишу результат, но пока висит уже более часа...



я, конечно, могу ошибаться, но попробуйте сами...
« Последнее редактирование: 30.06.2018, 00:12:25 от boa » Записан

Ничто не обходится нам так дешево и не ценится так дорого, как вежливость...  Мигель Сервантес де Сааведра

Юрий М
Глобальный модератор
Ветеран
*****

Репутация: +112/-0
Офлайн Офлайн

Сообщений: 2 077



Просмотр профиля E-mail
« Ответ #14 : 30.06.2018, 21:55:24 »

Странно... Всегда удаление диапазоном выигрывало по скорости с поочерёдным удалением каждой подходящей строки.
Очень долго формируется DelRa.
Записан
Юрий М
Глобальный модератор
Ветеран
*****

Репутация: +112/-0
Офлайн Офлайн

Сообщений: 2 077



Просмотр профиля E-mail
« Ответ #15 : 30.06.2018, 22:04:44 »

Проверил на 1 000 (466) строк - d_rows_2 немного выигрывает у обоих вариантов.
« Последнее редактирование: 30.06.2018, 22:13:51 от Юрий М » Записан
RAN
Эксперты
Старожил
*

Репутация: +43/-0
Офлайн Офлайн

Сообщений: 440



Просмотр профиля E-mail
« Ответ #16 : 01.07.2018, 23:22:43 »

Подготовлено 466 строк для удаления из массива в 1000 строк.
DelRowsRS - 0,0859375
d_rows_1 - 0,1015625
d_rows_2 - 0,078125
delFilter - 4,867188

УдалениеСтрокОднимМахом - 0,1796875
Подготовлено 4666 строк для удаления из массива в 10000 строк.
DelRowsRS - 1
d_rows_1 - 1,296875
d_rows_2 - 3,546875
УдалениеСтрокОднимМахом - 78,05469 Снят с дистанции
delFilter - 47,90625

Подготовлено 14000 строк для удаления из массива в 30000 строк.
DelRowsRS - 9,476563
d_rows_1 - 12,92188
d_rows_2 - 76,78906 Снят с дистанции
delFilter - 141,5078 Снят с дистанции

Фильтр сильно разочаровал  Грустный

Подготовлено 46666 строк для удаления из массива в 100000 строк.
DelRowsRS - 105,1563
d_rows_1 - 138,2578

Подготовлено 93334 строк для удаления из массива в 200000 строк.
DelRowsRS - 372,1094
d_rows_1 - 525,3906

Код: (vb)
Sub delFilter()
    Dim t!, lr&
    t = Timer
    Application.ScreenUpdating = False
    lr = Cells(Rows.Count, 1).End(xlUp).Row
    ActiveSheet.Range("A1:A" & lr).AutoFilter _
    Field:=1, Criteria1:=RGB(255, 255, 0), Operator:=xlFilterCellColor
    ActiveSheet.AutoFilter.Range.Offset(1).EntireRow.Delete
    ActiveSheet.AutoFilter.Range.AutoFilter
    Debug.Print "delFilter - " & Timer - t
    Application.ScreenUpdating = True
End Sub

Код: (vb)
Sub DelRowsRS()
    Dim lr&, n&, i&, ii&
    Dim sF$, s$, spl
    Dim k: k = 4
    Application.ScreenUpdating = False
    lr = Cells(Rows.Count, 1).End(xlUp).Row
    n = ActiveSheet.UsedRange.Row
    s = "A"
    For i = lr To n Step -1
         If Cells(i, 1).Interior.ColorIndex = 6 Then GoSub sRange
    Next
    If Len(s) Then sF = sF & "|" & Left(s, Len(s) - 2)
    If Len(sF) Then
        spl = Split(sF, "|")
        For i = 1 To UBound(spl)
            Range(spl(i)).EntireRow.Delete
            k = k + 1
        Next
    End If
    Application.ScreenUpdating = True
    Exit Sub
sRange:
                s = s & i & ",A"
            '        =====check len===============
            ii = ii + Len(Format(i, 0)) + 2
            If ii >= 248 Then
                sF = sF & "|" & Left(s, Len(s) - 2)
                s = Left(s, Len(s) - 2)
                ii = 0
                s = "A"
            End If
            '        ====================
Return
End Sub

Комментарий администратора убрал лишние $ в коде, чтобы код не задваивался.
« Последнее редактирование: 04.07.2018, 08:55:24 от Дмитрий Щербаков(The_Prist) » Записан

А что ты умеешь?
Учиться...
RAN
Эксперты
Старожил
*

Репутация: +43/-0
Офлайн Офлайн

Сообщений: 440



Просмотр профиля E-mail
« Ответ #17 : 02.07.2018, 09:56:02 »

Предыстория создания алгоритма http://www.excelworld.ru/forum/10-36917-1
Записан

А что ты умеешь?
Учиться...
Страниц: 1 2 [Все]   Вверх
Печать
Перейти в:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2006-2011, Simple Machines Valid XHTML 1.0! Valid CSS!
Яндекс.Метрика Рейтинг@Mail.ru