Страницы: 1 2 След.
RSS
VBA Заполнение массива из выбранных ячеек
 
Здравствуйте Уважаемые Форумчане  
Прошу помочь разобраться  
Пару месяцев назад написал для себя код с простым циклом для формирования отчётности, работает, но тормозит на большом объёме...  
Слышал умные люди говорят что массивы быстрее бегают  
Однако доделать до конца не получается...  
Прилагаю упрощённый файл с кодом как было и свои потуги переписать с использованием массивов  
Мои Вопросы в теле кода  
Спасибо
 
У Вас ошибка в самом принципе работы с массивом - можно конечно делать и так, как Вы (не вдаваясь в детали), но так пропадает весь выигрыш в скорости.  
С массивами нужно работать так:  
1. одним движением берём исходные данные в массив (и с листом больше не работаеи)  
2. одним движением создаём массив для результатов работы - размером, чтоб всё поместилось.  
3. перебираем данные в массиве, перекладываем отобранное в массив-результат.  
4. одним движением выгружаем результат на лист.  
 
Если, как в Вашей задаче, нужно переставлять местами столбцы, то это можно сделать в момент перекладывания данных (просто брать их в нужном порядке), или изначально брать данные не в один массив, а в несколько параллельных. Потом перебираем один, а перекладываем из нескольких параллельных.
 
Да, ещё важно - если предвидится большое количество строк - то тип Integer для переменной числа строк не годится, ставьте Long.  
Я вообще всегда ставлю Long или Byte, если до 256.
 
Hugo, спасибо за ответ, во всём с Вами согласен безусловно!  
Просто моё знакомство с VBA к сожалению носит пока урывочный характер, никак до конца не окунуться и застреваю пока на простом. О том чтобы перебрать данные в самом массиве пока что и не мечтаю, мне бы их пока туда просто загнать :)  
А не могли бы Вы посоветовать примеры решения схожих с моей задачи, в поиске ничего не нашёл, а у Уокенбаха для массивов самые простые примеры в учебнике...
 
Сейчас Ваш код переделывать некогда, другим занят.  
Но взять в массив просто:  
 
Dim a  
a=[a1:b100]
 
Вот у Вас в массиве a данные из 200 ячеек. Содержимое массива смотрите в окне Locals.
 
Hugo, байт до 256 не пойдет. Ошибка будет)
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


https://github.com/nervgh
 
Счас поищу - что-то мне казалось, что до как раз (т.е. 255 включительно :))
 
Ну да,  
The Byte data type can hold positive values from 0 to 255  
т.е. можно и к 256 приспособить :)
 
>>a=[a1:b100].Value
Я сам обалдел, кода первый раз увидел) Бац, и массив)  
 
Sub io()  
Dim v, x  
With Sheets("СПБ")  
v = .Range(.[A3], .Cells(.UsedRange.Rows.Count, "R")).Value ' массив таблицы
ReDim x(1 To UBound(v), 1 To 18)  
End With  
End Sub
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


https://github.com/nervgh
 
>>приспособить  
эт да, но значение 256 не примет)
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


https://github.com/nervgh
 
255+1 :)
 
Т.е. всего их 256.  
И я ведь написал  "до 256", но не написал "включительно" :)
 
Вот, переделал Ваш Sub Формирование_Отгрузки_ЦИКЛ() на массив:  
 
 
Sub Формирование_Отгрузки_МАССИВ()  
   On Error Resume Next  
   Sheets("СПБ").ShowAllData    'Снимаем условия фильтрации, если они есть  
   'тут надо сделать динамическое определение заполненного диапазона для очистки!  
   Sheets("ОТГРУЗКА").Range("A3:J99").ClearContents    'Очищаем предыдущие результаты выборки  
   Dim Row As Long    ' количество строк для прохода циклом  
   Dim NRow As Long    '№ строки для вставки результата в отгруз. листе  
   Dim Data_Otgr As Date    'дата на которую формируем отгрузку  
   Dim a    'это будет исходный массив  
   '  
   Data_Otgr = InputBox("Введите дату отгрузки товара в формате ДД.ММ.ГГ")  
   If Data_Otgr = Empty Then Exit Sub  
 
   'берём исходные данные в массив  
   With Sheets("СПБ")  
       a = .Range("R3:A" & .Cells(.Rows.Count, 1).End(xlUp).Row)  
   End With  
 
   'создаём массив для результата отбора  
   'высота с исходный, ширина как нужно  
   ReDim b(1 To UBound(a), 1 To 9)  
     
   'перебор массива  
   For Row = 1 To UBound(a)  
       If Data_Otgr = a(Row, 12) Then  
           NRow = NRow + 1  
           '===>  
           b(NRow, 1) = a(Row, 4)    'Заявка  
           b(NRow, 2) = a(Row, 8)    'Материал  
           b(NRow, 3) = a(Row, 1)    'Кто  
           b(NRow, 4) = a(Row, 2)    'Кому  
           b(NRow, 5) = a(Row, 3)    'Договор  
           b(NRow, 7) = a(Row, 9)    'Наименование  
           b(NRow, 8) = a(Row, 10)    'Кол -во  
           b(NRow, 9) = a(Row, 18)    'Цена  
           '===>  
       End If  
   Next Row  
   Sheets("ОТГРУЗКА").Range("I1") = Data_Otgr  
   If NRow = 0 Then  
       MsgBox "На данную дату отгрузок нет!"  
   Else  
       'выгрузка результатов  
       Sheets("ОТГРУЗКА").Range("A3:I3").Resize(NRow) = b  
   End If  
End Sub
 
Что-то я там перемудрил в этой части... Так ведь хотел написать :)  
 
 
   'берём исходные данные в массив  
   With Sheets("СПБ")  
       a = .Range(.[R3], .Cells(.Rows.Count, 1).End(xlUp))
   End With
 
Да, ещё - использовать имя Row для переменной не есть хорошо...  
Я обычно использую i, ii, iii и т.д. для циклов - тут бы как раз вместо Row взять i, а вместо NRow взять ii.
 
Еще немного извращений ^_^  
 
вместо  
 
b(NRow, 1) = a(Row, 4) 'Заявка  
b(NRow, 2) = a(Row, 8) 'Материал  
b(NRow, 3) = a(Row, 1) 'Кто  
b(NRow, 4) = a(Row, 2) 'Кому  
b(NRow, 5) = a(Row, 3) 'Договор  
b(NRow, 7) = a(Row, 9) 'Наименование  
b(NRow, 8) = a(Row, 10) 'Кол -во  
b(NRow, 9) = a(Row, 18) 'Цена  
 
это  
 
Dim v, j As Byte  
v = Array(4, 8, 1, 2, 3, 9, 10, 18)  
       For j = 0 To UBound(v)  
           b(NRow, j + 1) = a(Row, v(j))  
       Next
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


https://github.com/nervgh
 
Счас совсем человека запутаешь :)  
 
Я взял код как есть и с минимальными изменениями переделал на массив - если два кода поставить рядом, то хорошо видно, что на массиве даже код проще и по объёму меньше, чем при работе с ячейками напрямую.
 
>>на массиве даже код проще и по объёму меньше, чем при работе с ячейками напрямую.  
не скажи...  
 
>>Счас совсем человека запутаешь :)  
зато Byte впаяли ^_^
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


https://github.com/nervgh
 
совсем забыл, Dim b )))
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


https://github.com/nervgh
 
HUGO, категорически благодарю!  
 
Код отлично работает, все замечания учту. Главный принцип осознал.  
 
nerv, спасибо за участие, Ваши дополнения очень кстати тем более у самого были мысли задать последовательность столбцов в исходном массиве с помощью одномерного массива, не знал только как. Однако эта конструкция:  
Dim v, j As Byte  
v = Array(4, 8, 1, 2, 3, 9, 10, 18)  
For j = 0 To UBound(v)  
b(NRow, j + 1) = a(Row, v(j))  
у меня не совсем корректно работает, так в массиве с результатами отбора есть пустые столбцы (в полном коде в них подтягиваю данные формулами)  
b(NRow, 5) = a(Row, 3) 'Договор        с 5  
b(NRow, 7) = a(Row, 9) 'Наименование   перескакиваем на 7  
ну это мои заморочки:)  
 
не пойму только, как это работает, я разглядел в этом только последний столбец исходных данных, а "загоняется"  все данные  
a = .Range(.[R3], .Cells(.Rows.Count, 1).End(xlUp))
что означают эти точки, в них наверное всё дело :)  
 
Про окно Locals, не знал - классно!  
 
Вопрос: есть какие то ограничения для занесения данных в массив, у меня например потенциально будет 25 столбцов и 10 000 строк, будут ли операции с массивами в памяти корректно и быстро работать?
 
with Sheets(1) ' C объектом  
' точка - обращение к with Sheets(1) (т.е. объекту)  
'Диапазон(Верхняя правая ячейка, ОтВерхнейЛевойКАоследнейЯчейке этого(1) столбца).Значения  
a = .Range(.[R3], .Cells(.Rows.Count, 1).End(xlUp)).value
end with
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


https://github.com/nervgh
 
a = .Range(.[A3], .Cells(.UsedRange.Rows.Count, "R")).Value
как у nerv, и  
a = .Range("R3:A" & .Cells(.Rows.Count, 1).End(xlUp).Row)  
и  
a = .Range(.[R3], .Cells(.Rows.Count, 1).End(xlUp))
это всё одно и тоже - в массив берётся диапазон от A3 до Rx (или если смотреть по другой диагонали, то от R3 до Ax).  
Только эта x у меня определяется по столбцу A, а у nerv по столбцу R.  
Ещё есть вариант:  
a = .Range("A3:R" & .Cells(.Rows.Count, 1).End(xlUp).Row)  
 
Насчёт " в массиве с результатами отбора есть пустые столбцы (в полном коде в них подтягиваю данные формулами)" - при выгрузке массив затрёт все данные под ним, в том числе своим пустым столбцом тоже.  
Если в месте выгрузки уже есть в этом столбце формулы, и их нужно оставить, то тогда делайте два или больше параллельных массивов (одинаковой высоты)- один выгрузите перед столбцом с формулами, другой после.  
А работа с заполнением массивов ничем не отличается (они ведь идут параллельно), например:  
 
b(NRow, 1) = a(Row, 4) 'Заявка  
b(NRow, 2) = a(Row, 8) 'Материал  
c(NRow, 1) = a(Row, 1) 'Кто  
c(NRow, 2) = a(Row, 2) 'Кому  
...  
'выгрузка результатов  
Sheets("ОТГРУЗКА").Range("A3:B3").Resize(NRow) = b  
'выгрузка результатов  
Sheets("ОТГРУЗКА").Range("D3:E3").Resize(NRow) = c
 
Пусть затирает, меня устраивает, в моём коде данные подтягиваю после вставки массива.  
На скрине видны различия как заполняется результирующий массив  в исходном варианте, и предложного Nerv, мне нужна эта пустая строчка (6), пока нужна, пока шаблон отчётности не переделал :) А может буду просто столбец потом вставлять.
 
Эта строчка как раз понятна  
a = .Range("R3:A" & .Cells(.Rows.Count, 1).End(xlUp).Row)  
 
Сбило с толку именно отсутствие указания на столбец "A" здесь:  
a = .Range(.[R3], .Cells(.Rows.Count, 1).End(xlUp))
или по умолчанию берётся первый столбец? Где тут "A" - не пойму!
 
\массив массивов : )
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


https://github.com/nervgh
 
Тут    
a = .Range(.[R3], .Cells(.Rows.Count, __@@ 1="A" @@__).End(xlUp))
Первый столбец
 
1 - номер столбца  
 
v = Array(Array(1, 2, 3, 4, 5, 7, 8, 9), Array(4, 8, 1, 2, 3, 9, 10, 18)) ' массив массивов  
 
               For j = 0 To 7  
                   b(i, v(0)(j)) = a(q, v(1)(j))  
               Next
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


https://github.com/nervgh
 
{quote}{login=RAN}{date=14.10.2011 03:04}{thema=}{post}Тут    
a = .Range(.[R3], .Cells(.Rows.Count, __@@ 1="A" @@__).End(xlUp))
Первый столбец{/post}{/quote}  
 
Да уж, хорош я, ничего не скажешь! Спасибо.
 
{quote}{login=nerv}{date=14.10.2011 03:03}{thema=}{post}\массив массивов : ){/post}{/quote}  
Nerv, спасибо, но не дорос я ещё до такого кода. Понадобиться что-то осознанно изменить и буду весь день думать. Оставлю прежний вариант, а этот отложу на будущее для разбора.
 
Ваше право. Впрочем, если бы Вы сказали, что именно не понятно, мы попытались объяснить)
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


https://github.com/nervgh
Страницы: 1 2 След.
Наверх