Страница: 1 |
Страница: 1 |
Вопрос: как ускорить выполнение программы?
Добавлено: 02.07.08 10:40
Автор вопроса: APS | ICQ: 234458121
Есть программа с 3 вложенными циклами:
With Worksheets(n).UsedRange
endpoint = .Cells(.Rows.Count, .Columns.Count).Row
End With
For i = 2 To endpoint
oItem = Worksheets(n).Cells(i, 2)
For m = 2 To 4
Set oFind = Worksheets(m).Columns("A").Find(what:=oItem)
If Not oFind Is Nothing Then
r = Worksheets(n).Cells(i, 6)
d = Worksheets(n).Cells(i, 7)
s = Worksheets(n).Cells(i, 8)
oFind.Offset(0, 7) = r
oFind.Offset(0, 8) = d
oFind.Offset(0, 9) = s
GoTo 50
End If
50: Next
Next
Next
Смысл в следующем. Есть дву группы листов с данными: одна группа из 3 листов и вторая из двух. Все листы заполнены практически полностью, т.е. занято от 40 до 60 тысяч строк. Необходимо найти совпадающие артикулы в двух группах листов и перенести цены из одной группы в другую.
Вышеприведенный код у меня выполнялся порядка 3-х часов. Можно как-то оптимизировать этот код, чтобы сократить время хотя бы втрое.
Ответы
Всего ответов: 15
Номер ответа: 1
Автор ответа:
Smith
ICQ: adamis@list.ru
Вопросов: 153
Ответов: 3632
Профиль | | #1
Добавлено: 02.07.08 10:58
Это конечно не ответ на главный вопрос, но
endpoint = Worksheets(n).UsedRange.Rows.Count
вродебы достаточно, нафига там With End With?
Номер ответа: 2
Автор ответа:
FIX
ICQ: 348680795
Вопросов: 39
Ответов: 62
Профиль | | #2
Добавлено: 02.07.08 14:26
Попробуй во всех циклах заменить: For m = 2 To 4
на следующее:
Dim a=2,b=4 'объявить перед циклами
For m = a To b' заменить
смысл в том что в твоем примере под 2 и 4 каждый раз выделяется область памяти, а в моем эта область просто считывается.
если цикл действительно большой, то это будет быстрее
Номер ответа: 3
Автор ответа:
Smith
ICQ: adamis@list.ru
Вопросов: 153
Ответов: 3632
Профиль | | #3
Добавлено: 02.07.08 14:35
Переменные вообще отдельная тема.
APS покажи где ты их объявил.
Номер ответа: 4
Автор ответа:
Smith
ICQ: adamis@list.ru
Вопросов: 153
Ответов: 3632
Профиль | | #4
Добавлено: 02.07.08 14:41
GoTo 50 и 50: убери, это лишнее.
Номер ответа: 5
Автор ответа:
APS
ICQ: 234458121
Вопросов: 38
Ответов: 107
Профиль | | #5
Добавлено: 02.07.08 22:17
Переменные не объявлял.
Goto 50 осталось от старой программы с более сложными условиями.
Номер ответа: 6
Автор ответа:
APS
ICQ: 234458121
Вопросов: 38
Ответов: 107
Профиль | | #6
Добавлено: 02.07.08 22:19
Реально, with лишнее. Я брал это по чьему совету на форуме достаточно давно.
Номер ответа: 7
Автор ответа:
Smith
ICQ: adamis@list.ru
Вопросов: 153
Ответов: 3632
Профиль | | #7
Добавлено: 03.07.08 08:10
В самый верх кода впиши
Dim N As Long, M As Long, I As Long
Dim oItem As String, oFind As Range
Dim R As String, D As String, S As String
и проверь, может быстрее заработает
Номер ответа: 8
Автор ответа:
Jasmin
Вопросов: 23
Ответов: 417
Профиль | | #8
Добавлено: 03.07.08 08:39
oFind.Offset(0, 8) = Worksheets(n).Cells(i, 7)
oFind.Offset(0, 9) = Worksheets(n).Cells(i, 8)
Тогда не нужны переменные и область памяти не занимается.
Номер ответа: 9
Автор ответа:
Jasmin
Вопросов: 23
Ответов: 417
Профиль | | #9
Добавлено: 03.07.08 08:45
Артикулы на листе уникальны ? Если да, то после того как нашли очередной артикул и перенесли цену (вместо строки Goto 50) написать Exit For. Чтобы не гонять остаток цикла. Или заменить цикл на Do LOOP
Номер ответа: 10
Автор ответа:
Jasmin
Вопросов: 23
Ответов: 417
Профиль | | #10
Добавлено: 03.07.08 08:49
Сорри, пропустила m это номер листа. Поправка: Артикулы на листАХ уникальны ?
Номер ответа: 11
Автор ответа:
Artyom
Разработчик
Вопросов: 130
Ответов: 6602
Профиль | | #11
Добавлено: 03.07.08 16:23
Объектная модель Excel не очень шустрая, сам сейчас с этим столкнулся.
Смешные советы типа убрать переменные можешь не рассматривать - экономия десятка байт на обработке 40К строк не даст никакого выигрыша.
Если артикулы уникальны, попробуй сделать встроенными формулами Excel, например SumIf, CountIf (кажется к русской редакции Excel СуммЕсли и КоличествоЕсли, или что-то подобное).
Номер ответа: 12
Автор ответа:
Artyom
Разработчик
Вопросов: 130
Ответов: 6602
Профиль | | #12
Добавлено: 03.07.08 16:25
Еще перед обработкой можно отсортировать данные на листах по артикулу, тогда не нужен будет
Будет более сложный алгоритм, но он обойдется одним циклом без этого Find, который, как я понимаю, тоже не очень шустрый.
Номер ответа: 13
Автор ответа:
ADSemenov.ru
Вопросов: 5
Ответов: 276
Web-сайт:
Профиль | | #13
Добавлено: 03.07.08 20:55
Всё загнать сначала в память и там всё сделать. Результат записать на лист.
Номер ответа: 14
Автор ответа:
Artyom
Разработчик
Вопросов: 130
Ответов: 6602
Профиль | | #14
Добавлено: 03.07.08 22:12
ну да, можно и так
Номер ответа: 15
Автор ответа:
Jasmin
Вопросов: 23
Ответов: 417
Профиль | | #15
Добавлено: 04.07.08 06:45
Порой формулами работает гораздо дольше, чем макросом. К тому же при изменении любой ячейки будут пересчитываться все формулы, что сильно замедляет работу, если нужно сначала внести N данных. Можно конечно отключить пересчет, но при этом про это необходимо помнить, что его нужно потом включить/пересчитать вручную.
Хотя можно конечно попробовать сделать через формулы.