powered by simpleCommunicator - 2.0.19     © 2024 Programmizd 02
Map
Форумы / Visual Basic [игнор отключен] [закрыт для гостей] / Очень долгий перебор строк в цикле
25 сообщений из 62, страница 1 из 3
Очень долгий перебор строк в цикле
    #40077851
Markovich21
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Доброго времени суток, уважаемые форумчане! В макросах не силен, по статейкам в инете написал код. Смысл такой, что в таблицу сначала вставляется необходимое количество строк, затем из буфера обмена (ранее скопированного диапазона в excel) вставляется в диапазон ячеек таблицы word (выбирается таблица №3). Далее перебираются ячейки 3 столбца и при условии, что в ячейке 3 символа, копируется в буфер содержимое ячейки второго столбца, строка очищается, ячейки в строке объединяются и затем в строку вставляется ранее скопированное содержимое ячейки второго столбца, ну и для красоты ячейка затемняется. Проблема в том, что в случае, например, двухста строк код выполняется более менее быстро, а вот когда строк, например, две тысячи, код выполняется настолько долго, что через 15-20 минут, не дождавшись окончания, снимаю задачу диспетчером. Не могу понять, что можно предпринять для исправления.
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
Sub Import()
On Error Resume Next
Application.ScreenUpdating = False
Dim i As Long
    With ActiveDocument
    n = Val(InputBox("Сколько строк в таблице?"))
    If n = 0 Then Exit Sub
    k = n - 1 'корректировка количества строк
    r = n + 1 'корректировка количества строк
        With .Tables(3) 'обращаюсь к третьей таблице
        .Rows(2).Select 'выбираю позицию для добавления строк
        Selection.InsertRowsBelow k 'вставвка заданного количества строк
        .Rows(1).Borders(wdBorderBottom).LineStyle = wdLineStyleDouble 'красявости
        .Rows(r).Borders(wdBorderBottom).LineStyle = wdLineStyleDouble 'красявости
        rs = .Cell(2, 2).Range.Start 'начало дипазона для вставки
        re = .Cell(r, 6).Range.End 'конец дипазона для вставки
        ActiveDocument.Range(rs, re).Paste 'вставка из буфера в заданный диапазон
            For i = 2 To r
                If .Cell(i, 3).Range.Characters.Count = 3 Then 'определение строки для форматирования
                .Cell(i, 2).Range.Copy 'копирую в память содержимое ячейки
                .Rows(i).Range.Delete Unit:=wdCharacter, Count:=1 'очистка строки
                .Cell(i, 1).Merge MergeTo:=.Cell(i, 6) 'объединение ячеек
                .Rows(i).Range.Paste 'вставка ранее запомненного значения
                .Rows(i).Shading.BackgroundPatternColor = wdColorGray15 'красявости
                End If
            Next
        End With
    End With
Application.ScreenUpdating = True
End Sub



Подскажите, пожалуйста, в чем ошибка в коде, существует ли способ ли ускорить его выполнение? Заранее спасибо.
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40077859
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Во-первых, тут очень много копирования в буфер. Это занимает очень много времени. По возможности, нужно избежать копирования в буфер, лучше копировать в переменную (если речь идет о значении, если, конечно, речь идет только о значении, а не о формулах, оформлении и прочем)

Во-вторых, любое взаимодействие с ячейками листа тоже достаточно медленное. Поэтому, лучше минимально задействовать такое взаимодействие в цикле и активно использовать массивы, копируя и вставляя значения разом из массива / в массив.
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40078146
Markovich21
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Shocker.Pro, большое Вам спасибо за отзыв. По первому пункту понятно в каком направлении работать, а на счет второго пункта я не совсем понял, каким образом должна происходить работа с массивом, разом копировать и вставлять, если по выполнению условия в ячейке изменяется строка. Буду очень благодарен, если немного подробней объясните как это должно работать.
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40078150
Фотография Akina
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Markovich21
каким образом должна происходить работа с массивом, разом копировать и вставлять, если по выполнению условия в ячейке изменяется строка.

Она изменяется, потому что там имеется зависимая формула?
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40078156
vb_sub
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Shocker.Pro,
столкнулся с таким кейсом-нужно обработать таблицу с листа Excel через предварительное загнание её в массив, но для обработки нет необходимости загонять всю таблицу в массив- нужно только 2 столбца из 20 к примеру. Но быстрым методом копирования диапазона в массив
Код: vbnet
1.
   SetTimingRange = Range(.Cells(2, 1), .Cells(rowCount, columnCount)).Value2


можно загнать только всю таблицу целиком в массив.
Получается, чтобы заполнить массив только 2 столбцами, а не всей таблицей, нужно делать цикл по ячейкам, который медленнее, чем Range.Value и вручную их копировать в массив. Соответственно, можно ли несколько Range склеить в один массив без цикла по ячейкам?
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40078165
Фотография Akina
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
vb_sub
Но быстрым методом копирования диапазона в массив

можно загнать только всю таблицу целиком в массив.

А указать в Range только нужные столбцы идея не приходила? типа
Код: vbnet
1.
SetTimingRange = Range(.Cells(2, 1), .Cells(rowCount, 2)).Value2
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40078168
vb_sub
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Akina,
Range это непрерывный диапазон, нельзя указать крайние столбцы и исключить некоторые промежуточные из них.
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40078182
Markovich21
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Akina, я может что то не понимаю, но у меня word и формулы в строке нет. Изменяется строка i (объединяются ячейки и в них вставляется текстовое значение из ячейки второго столбца), если в ячейке третьего столбца 3 символа
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40078183
Фотография big-duke
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
vb_sub
Akina,
Range это непрерывный диапазон

Это не так.
Код: vbnet
1.
Range("A1,B:C,f:f,16:17,20:20").Select
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40078190
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Markovich21
у меня word
о боже *FACEPALM*!
Я не заметил слона!

Думаю, что все вышестоящие ответы можно вычеркнуть.

Автору - надо ЯВНО указывать среду разработки, но мы, конечно, тоже хороши!
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40078207
Markovich21
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Shocker.Pro, виноват, каюсь, в будущем учту замечание. И все же для word существует решение данной проблемы?
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40078291
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
С вордом всё сложнее, надо возиться и пробовать.

Попробуй для начала убрать работу с буфером внутри цикла. Может это решит проблему до приемлемой скорости.

ЗЫ: Лучше работать с ThisDocument вместо ActiveDocument
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40078409
Markovich21
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Shocker.Pro, спасибо за ответы с наводками. Использовал переменную внутри цикла вместо буфера, скорость выполнения кода действительно возрасла. Теперь хотя бы на двух тысячах строках можно дождаться завершения работы макроса. Код выглядит так:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
Sub ImportMetallTest()
Application.ScreenUpdating = False
Dim i As Integer
Dim S As String
    With ActiveDocument
    N = Val(InputBox("Сколько строк в таблице?"))
    If N = 0 Then Exit Sub
    k = N - 1
    R = N + 1
        With .Tables(3)
        .Rows(2).Select
        Selection.InsertRowsBelow k
        rs = .Cell(2, 2).Range.Start
        re = .Cell(R, 6).Range.End
        ActiveDocument.Range(rs, re).Paste
           For i = 2 To R
               If .Cell(i, 3).Range.Characters.Count = 3 Then
               S = .Cell(i, 2).Range
               .Rows(i).Range.Delete Unit:=wdCharacter, Count:=1
               .Cell(i, 1).Merge MergeTo:=.Cell(i, 6)
               .Rows(i).Range = S
               End If
           Next
       End With
    End With
Application.ScreenUpdating = True
End Sub


Но возникла проблема, что после вставленной переменной отрабатывается Enter и ячейка становится как бы двустроковой. Можно этого как то избежать?
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40078415
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Для начала отформатируем, чтобы хоть читать код можно было
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
Sub ImportMetallTest()

Application.ScreenUpdating = False
Dim i As Integer
Dim S As String
With ActiveDocument
    N = Val(InputBox("Сколько строк в таблице?"))
    If N = 0 Then Exit Sub
    k = N - 1
    R = N + 1
    With .Tables(3)
        .Rows(2).Select
        Selection.InsertRowsBelow k
        rs = .Cell(2, 2).Range.Start
        re = .Cell(R, 6).Range.End
        ActiveDocument.Range(rs, re).Paste
        For i = 2 To R
            If .Cell(i, 3).Range.Characters.Count = 3 Then
                S = .Cell(i, 2).Range
                .Rows(i).Range.Delete Unit:=wdCharacter, Count:=1
                .Cell(i, 1).Merge MergeTo:=.Cell(i, 6)
                .Rows(i).Range = S
            End If
        Next
    End With
End With
Application.ScreenUpdating = True

End Sub
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40078416
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Попробуй копировать в переменную не .Range а .Range.Text
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40078468
Markovich21
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Shocker.Pro, таким вот образом не помогло:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
        For i = 2 To R
            If .Cell(i, 3).Range.Characters.Count = 3 Then
                S = .Cell(i, 2).Range.Text
                .Rows(i).Range.Delete Unit:=wdCharacter, Count:=1
                .Cell(i, 1).Merge MergeTo:=.Cell(i, 6)
                .Rows(i).Range = S
            End If
        Next


Все-равно откуда то присутствует символ "конец абзаца"
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40078486
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну значит надо его грохнуть прям в переменной
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40078535
istrebitel
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vb_sub
Range это непрерывный диапазон, нельзя указать крайние столбцы и исключить некоторые промежуточные из них.

Можно использовать несколько Range, по одному на каждую необходимую колонку.
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40078813
Markovich21
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Shocker.Pro, несколько другим способом пытаюсь решить проблему скорости выполнения цикла. Как Вы и советовали, отказался от копирования в буфер внутри цикла. Получился код:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
Sub ImportTest1()

Application.ScreenUpdating = False
Dim i As Integer
Dim S As String
With ActiveDocument
    N = Val(InputBox("Сколько строк в таблице?"))
    If N = 0 Then Exit Sub
    k = N - 1
    R = N + 1
    With .Tables(3)
        .Rows(2).Select
        Selection.InsertRowsBelow k
        rs = .Cell(2, 2).Range.Start
        re = .Cell(R, 6).Range.End
        ActiveDocument.Range(rs, re).Paste
        For i = 2 To R
            If .Cell(i, 3).Range.Characters.Count = 3 Then
                .Cell(i, 1).Merge MergeTo:=.Cell(i, 6)
                .Rows(i).Range = Left(.Rows(i).Range, Len(.Rows(i).Range) - 13)
            End If
        Next
    End With
End With
Application.ScreenUpdating = True

End Sub


В нем в строке, найденной по условию, сначала объединяются ячейки; в объединенной ячейке остается содержимое второй ячейки с множеством скрытых символов, которые обрезаются; в итоге как плюс - не сбивается форматирование. Скорость выполнения кода заметно выше, но все-равно когда строк две тысячи выполняется он очень долго. Не могу разобраться как работать с ThisDocument. Если с ним работать тоже должен быть прирост скорости? Есть еще варианты над чем поработать? Спасибо.
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40078817
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
можно еще ускорить, избавившись от двойного обращения к .Rows(i).Range

чтобы ускорять еще - скорее всего уже нужно менять подход в принципе, а может это уже будет невозможно. Без файла образца сложно что-то сказать
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40078892
Markovich21
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Shocker.Pro, двойное обращение к .Rows(i).Range исключил. Вставил таймер, цикл по обработке двух тысяч строк выполняется 85 сек.
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
Sub ImportTest2()

Application.ScreenUpdating = False
Dim i As Integer
Dim S As String
With ActiveDocument
'    N = Val(InputBox("Сколько строк в таблице?"))
    N = 2000
'    If N = 0 Then Exit Sub
    k = N - 1
    R = N + 1
    With .Tables(3)
        .Rows(2).Select
        Selection.InsertRowsBelow k
        rs = .Cell(2, 2).Range.Start
        re = .Cell(R, 6).Range.End
        ActiveDocument.Range(rs, re).Paste
 tm = Timer
        For i = 2 To R
            If .Cell(i, 3).Range.Characters.Count = 3 Then
                .Cell(i, 1).Merge MergeTo:=.Cell(i, 6)
                S = .Rows(i).Range
                S = Left(S, Len(S) - 13)
                .Rows(i).Range = S
            End If
       Next
    End With
End With
Application.ScreenUpdating = True

MsgBox Timer - tm, 64

End Sub


Прилагаю файлы для примера. В таблице excel нажимаю кнопку "копировать в буфер", в word выполняю код. Т.к. два файла приложить не могу, поэтому выложил в архиве. Предполагаю, что можно сократить время, если передавать таблицу из excel в word напрямую, но как это сделать пока не знаю, да и все-таки основное время уходит на обработку строк в цикле, вот его бы ускорить
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40079841
Markovich21
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Shocker.Pro

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

Shocker.Pro, в чем может заключаться подход с другой стороны, имеется ввиду отказаться от цикла перебора ячеек?
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40079849
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я поэкспериментировал с этим кодом. Даже если просто убрать все внутренности цикла, тормозит сама проверка
Код: vbnet
1.
.Cell(i, 3).Range.Characters.Count = 3


Попытки обращения к ячейке другими способами результата особо не дали.

Я не знаю, какие у тебя возможности есть при манипуляции экселем, кроме копипасты
По большому счету, нужно заранее вычислить номера строк для объединения ячеек
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40079872
Markovich21
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Shocker.Pro, большое спасибо Вам за помощь и быстрые ответы. Может я делаю это криво, но в экселе, я специально ввожу в ячейку 3 символа, чтобы определить строку в которой нужно объединить ячейки, т.е. эти три символа в ячейке третьего столбца работают как маркер. Может есть какие то другие способы, более быстрые, по которым определить строку, в которой объединить ячейки? А про определение номеров строк для объединения в самом экселе... у меня в голове витала такая идея. Но она для меня какая то фантастическая. В самом экселе определить номера строк для определения сложностей нет (например, через те же три символа в ячейке), но фактически передать в ворд номера строк для объединения не представляю как реализовать. Количество строк и номера строк могут быть абсолютно разные. В экселе нужно выделить ячейку (диапазон) для номеров строк или как то через переменные эти номера передавать?
...
Рейтинг: 0 / 0
Очень долгий перебор строк в цикле
    #40079876
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Markovich21
я специально ввожу в ячейку 3 символа
это программно происходит или руками?
...
Рейтинг: 0 / 0
25 сообщений из 62, страница 1 из 3
Форумы / Visual Basic [игнор отключен] [закрыт для гостей] / Очень долгий перебор строк в цикле
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали тему (0):
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]