Страницы: 1 2 След.
RSS
VBA. Создание виртуальных массивов. Выгрузка массива на лист
 
Добрый день. Ищу человека который будет обучать меня программированию на vba in excel    
На условиях взаимообучения  
О себе Я близок к MCTS по SQL SERVER BI. Собственно и в Excel я не новичок. Но хотелось бы это обучение реализовать побыстрее. В целом по excel уверенный пользователь, но не такой конечно как на этом форуме, но цели пока такой и нет. Хотя бывает конечно если есть желание я захожу сюда и решаю какую-нибудь задачу.    
 
Что я знаю о vba.  
 
Знаю объектную модель Application, workbook, sheet, cell  
Знаю что такое переменные и как их объявлять dim i,j as variant    
Знаю чем метод отличается от свойства и области видимости  
Общее понимание циклов.    
Могу написать Msgbox "Hello world"  
В чем проблема/ зачем я все это пишу. Мне надоело читать книги по vba. Мне нужен толковый человек который мне на примерах объяснит что такое массивы и как с ними бороться и научить делать более менее сложную логику на vba  
В основном проблема с массивами. Требуется около 10 часов практических занятий, то есть по аське или как то так.    
 
Что я могу научить    
Информационная поддержка  
Установка SQL server c ноля  
Насторойка тестовых баз их описание  
Общие знания T-sql, хорошие знания sql 92 стандарта реально научу языку запросов sql, научу выбирать данные из одной и более таблиц  
Научу разбираться в джойнах, отличать левый от внутреннего  
Преобразования агрегация, типы. И много другого.    
Вставлять данные, удалять    
Проектирование БД общие вопросы  
Службы SSAS научу сделать куб  
SSRS научу развернуть службу построить отчет, параметры, оформление  
SSIS научу строить интеграционные пакеты. Расскажу о том как их делать.    
 
Кому это интересно обращайтесь на почту dmitriy8308@mail.ru
 
если честно, лучшая школа это:  
1) делать какое-либо задание для себя (по работе или учёбе)  
2) задавать вопросы на форуме и читать форум каждый день  
 
Я прочитал по Excel и VBA книг 20, но все прочитанные знания быстро забываются, если их не применять на практике. Я отдал все свои книги и перешёл на форум, читая ответы на вопросы других людей и пытаясь помочь другим людям быстрее осваиваешь материал и учишься.  
 
Перейдём к массивам, вот 3 примера работы с массивами  
 
Sub TestArray()  
   Dim iArray()  'объявляем массив  
   ReDim iArray(1 To 5) 'указываем размерность массива (5 элементов: от 1 до 5)  
     
   'ВАРИАНТ 1  
   'заполняем массив по-индексно названиями месяцев  
   iArray(1) = "Январь"  
   iArray(2) = "Февраль"  
   iArray(3) = "Март"  
   iArray(4) = "Апрель"  
   iArray(5) = "Май"  
   'MsgBox "3-й элемент массива равен: " & iArray(3)  
     
   Dim i As Long 'объявляем переменную типа Long (целое число)  
   For i = LBound(iArray) To UBound(iArray) 'цикл от нижней границе массива до верхней границе массива  
       MsgBox i & "-й элемент массива равен: " & iArray(i)  
   Next i  
     
   'ВАРИАНТ 2  
   'массив можно заполнить циклом  
   For i = LBound(iArray) To UBound(iArray) 'цикл от нижней границе массива до верхней границе массива  
       iArray(i) = i 'каждому индексу массива присваиваем его номер  
   Next i  
   MsgBox "4-й элемент массива равен: " & iArray(4)  
     
   'ВАРИАНТ 3  
   'давайте умножим каждый элемент массива на 3  
   For i = LBound(iArray) To UBound(iArray) 'цикл от нижней границе массива до верхней границе массива  
       iArray(i) = iArray(i) * 3 'каждой элемент массива умнажаем на 3  
   Next i  
   MsgBox "5-й элемент массива равен: " & iArray(5)  
End Sub  
 
 
Скопируйте этот код в редактор VBA (только копировать в РУССКОЙ РАСКЛАДКЕ КЛАВИАТУРЫ) и запустите его через F8 (пошаговый режим) и нажимайте F8 до конца макроса, вы увидите как работает код, а комментарии вам помогут понять смысл массивов.    
 
Если что-то будет не понятно, спрашивайте  
 
Павел
 
Теперь давайте попробуем применить массивы к данным на листе Excel  
 
 
Sub TestArray2()  
   Dim iArray()  'объявляем массив. Размерность массива ниже в коде не указываем.  
   Dim i As Long  
     
   'заполняем диапазон А1:А5 названиями месяцев  
   Range("A1") = "Январь"  
   Range("A2") = "Февраль"  
   Range("A3") = "Март"  
   Range("A4") = "Апрель"  
   Range("A5") = "Май"  
 
   'переносим данные из диапазона А1:А5 в массив  
   iArray = Range("A1:A5").Value  
   'теперь наш массив iArray имеет размерность (1 to 5, 1) - 5 строк и 1 столбец. т.е. он у нас ДВУМЕРНЫЙ  
   'давайте циклом посмотрим содержимое массива  
   For i = LBound(iArray) To UBound(iArray) 'цикл от нижней границе массива до верхней границы массива  
       MsgBox i & "-й элемент массива равен: " & iArray(i, 1) 'i - строка, 1 - это столбец  
   Next i  
   'а теперь давайте выгрузим обратно наш массив на лист в столбец С  
   'мы расширяем диапазон от ячейки С1 вниз на количество строк массива (5) и на 1 столбец  
   'логика - Ячейка(С1).РасширитьДиапазон(кол-во строк, кол-во столбцов) = наш_массив  
   Range("C1").Resize(UBound(iArray, 1), UBound(iArray, 2)) = iArray  
End Sub  
 
 
Так же скопируйте в русской раскладке код в VBE и запустите пошагово через F8.  
Что не понятно - спрашивайте  
 
 
Павел
 
Если для понимания нужно определение массива, то массив можно описать так:  
 
Массив — это именованный набор однотипных переменных, расположенных в памяти непосредственно друг за другом, доступ к которым осуществляется по индексу.  
 
Массивы бывают Одномерные, Двумерные и т.д.  
 
Двумерный массив - это как ячейки на листе Excel. Т.е. есть строки и есть столбцы.  
 
Если к Одномерному массиву можно обратиться так:    
 
переменная = Массив(5)    
 
То к Двумерному массиву нужно обращаться указывая и первый и второй индекс, например:  
 
Переменная = массив(5,3)  
 
Вот ещё один пример заполнения ОДНОМЕРНОГО массива  
 
 
Sub Test3()  
   Dim iArray()  
   'заполнять массив можно так же через функцию Array  
   'нужно учесть, что первый индекс будет начинаться с 0, а не с 1  
   iArray = Array("Январь", "Февраль", "Март", "Апрель", "Май")  
   MsgBox "1-й элемент массива: " & iArray(1) & vbLf & "т.к. 0 элемент массива Январь", , ""  
End Sub  
 
 
Павел
 
Определение границ массива, на примере одномерного массива  
 
Sub TestArray4()  
   Dim iArray() 'объявляем динамический массив  
 
   'заполняем массив названиями месяцев  
   iArray = Array("Январь", "Февраль", "Март", "Апрель", "Май")  
 
   'определяем нижнюю и верхнюю границу массива  
   MsgBox "Массив содержит 5 элементов" & vbLf & _  
   "Нижняя граница массива равно индексу: " & LBound(iArray) & vbLf & _  
       "Верхняя граница массива равно индексу: " & UBound(iArray)  
End Sub  
 
 
Чтобы узнать границы, например, двумерного массива нужно писать так  
 
LBound(iArray,2)  
 
UBound(iArray,2)  
 
 
Павел
 
Давайте теперь рассмотрим пример работы с ДВУМЕРНЫМ массивом  
 
Sub TestArray5()  
     
   Dim iArray(1 To 5, 1 To 3) 'объявляем двумерных массив с размерностью 1 To 5, 1 To 3  
   Dim i As Long, n As Long '2 числовые переменные для работы с циклами  
     
   For i = LBound(iArray, 1) To UBound(iArray, 1) 'т.е. от 1 до 5  
       For n = LBound(iArray, 2) To UBound(iArray, 2) 'т.е. от 1 до 3  
           iArray(i, n) = i * n  
       Next n  
   Next i  
     
   'сейчас у нас массив такой  
   'iArray(1,1)  
   'iArray(1,2)  
   'iArray(1,3)  
   'iArray(2,1)  
   'iArray(2,2)  
   'iArray(2,3)  
   '..  
   '..  
   'iArray(5,1)  
   'iArray(5,2)  
   'iArray(5,3)  
     
   MsgBox "Верхний индекс ПЕРВОЙ размерости массива равен: " & UBound(iArray, 1) & vbLf & _  
       "Верхний индекс ВТОРОЙ размерости массива равен: " & UBound(iArray, 2) & vbLf & _  
       "Значение индекса 5,2 равен: " & iArray(5, 2)  
         
End Sub  
 
 
Так же скопируйте в русской раскладке клавиатуры код в редактор VBA и пожагово через F8 пройдитесь по коду  
 
 
Павел
 
Все примеры, приведённые в этой теме я поместил в файл Excel, чтобы вам было удобнее тестировать код. См. файл  
 
P.S. Код можно посмотреть нажав Alt+F11  
 
Павел
 
Студент++, здесь знаниями не отделаетесь, бутылкой тоже (не пьет). Готовьте большущую шоколадку :)
 
{quote}{login=Ластик}{date=22.01.2012 05:36}{thema=}{post}Все примеры, приведённые в этой теме я поместил в файл Excel, чтобы вам было удобнее тестировать код. {/post}{/quote}  
ОК. Спасибо Павел. Если что то нужно по тому (SQL BI) из того что я написал пишите мне на почту. Буду разбирать ваши примеры
 
{quote}{login=vikttur}{date=22.01.2012 06:01}{thema=}{post}Студент++, здесь знаниями не отделаетесь, бутылкой тоже (не пьет). Готовьте большущую шоколадку :){/post}{/quote}  
 
Это да
 
Студент++, можете мне на почту написать. В теле письма:  
 
1. Чему именно хотите научиться.  
2. Что уже знаете (если знаете).  
3. Знакомы ли Вы с синтаксисом vb?  
4. Для чего это Вам нужно?  
5. Изучали ли Вы и практиковались в других языках программирования?  
 
 
p.s.: я, конечно, не супер-профессионал, но тем не менее, могу кое-чему научить.
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


https://github.com/nervgh
 
Я помнится тоже не сразу массивы понял, пару раз на форуме спрашивал разъяснения. Resize тоже непонятная штука была :)  
Одно небольшое замечание по "Массив — это именованный набор однотипных переменных".  
Если массив типа Variant - т.е. как всюду в примерах, без явного указания типа массива, то в массиве могут храниться и числа, и даты, и строки. Т.е. что есть на листе - то и будет в массиве.  
С датами интересно -    
в ячейке значение 40909  
форматом выводит как 01.янв,  
а в массиве      
: a(1,1) : #01.01.2012# : Variant/Date  
 
Содержимое массивов удобно смотреть в окне Locals - сразу всё понятно, что где.
 
угу, но я не стал писать об этом, чтобы на начальном этапе не запутывать.    
А определение взял из Wikipedia  
<EM>http://ru.wikipedia.org/wiki/%C8%ED%E4%E5%EA%F1%ED%FB%E9_%EC%E0%F1%F1%E8%E2</EM>
 
У меня вот ещё какой вопросы есть по массивам:  
 
Если двумерный массив мы можем рассматривать как аналог рабочего лиса Excel, то:  
1. Можно ли в самом массиве оперировать с "Resize"  
2. Можно ли оперировать целой строкой или столбцом массива, аналог EntireColumn, EntireRow  
как работая с самим массивом, так и заполняя и выгружая с рабочего листа?
 
Ого какая хорошая тема:) я и сам с удовольствием почитал так как с массивами тоже толком еще не умею обращаться:) но насколько я понимаю - строка массива - это цикл с фиксированным номером строки и переменной номера столбца?
 
VDM, 2 -  это к слэну, он спец по CopyMemory, я это понять не могу :)  
Вот его пример кода:  
 
 
но можно еще быстрее - цикл copymemory по столбцам  
 
Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)  
Sub arrdel_str_copymem()  
arr = Range("A1:B5").Value  
Dim delStr&, j&, mr&  
delStr = 3: mr = UBound(arr)  
For j = 1 To UBound(arr, 2)  
CopyMemory arr(delStr, j), arr(delStr + 1, j), 16 * (mr - delStr)  
arr(mr, j) = Empty  
Next  
End Sub
 
{quote}{login=VDM}{date=22.01.2012 11:26}{thema=}{post}1. Можно ли в самом массиве оперировать с "Resize"  
2. Можно ли оперировать целой строкой или столбцом массива, аналог EntireColumn, EntireRow  
как работая с самим массивом, так и заполняя и выгружая с рабочего листа?{/post}{/quote}  
1-нет (можно увеличить последнюю размерность массива с помощью Redim Preserve)  
2-не понял чего хотите сотворить со строкой? с помощью функции index можно вытащить из двухмерного массива строку или столбец, и выгрузить их на лист или еще как нибудь приспособить :)
Спасибо
 
VDM,  
 
к сожалению, нельзя.    
 
Свойства Resize, EntireRow, EntireColumn - относятся только к ячейкам листа Excel.  
 
Как бы аналог Resize для массива это    
 
Redim массив(новая размерность)  
 
т.е. можно объявить массив, например, из 5 элементов  
 
Dim myArray (1 to 5)    
 
а потом его переопределить    
 
Redim myArrray (1 to 10)    
 
но при Redim - массив полностью очищается  
 
Чтобы он не очищался используют конструкцию ReDim Preserve  
 
ReDim Preserve массив (новая верхняя граница)  
 
Вот пример.    
1) Сперва мы создаём пустой динамический массив - в данном случае это не обязательно, т.к. Redim тоже создаёт массив  
2) через Redim определяем границы массива от 1 до 10 элементов  
3) заполняем массив данными  
4) увеличиваем верхнюю границу массива до 15 элементов  
 
Sub TestArary6()  
Dim myArray() 'объявляем динамический массив  
Dim i As Long  
 
   ReDim myArray(1 To 10)     'переопределяем размер массива (от 0 до 10 элементов)  
   For i = 1 To 10    ' цикл 10 раз  
       myArray(i) = i + 7  ' заполняем массив числами от 1 до 10  
   Next i  
   MsgBox "Значение 10-его элемента массива равно: " & myArray(10)  
         
   ReDim Preserve myArray(1 To 15)     'расширяем массив до 15 элементов с сохранением значений массива  
   MsgBox "Значение 10-его элемента массива равно: " & myArray(10) & vbLf & _  
       "Значение 12-его элемента массива равно: (пусто) " & myArray(12)  
 
End Sub  
 
 
НО!!! Нужно знать, что через ReDim Preserve можно изменять вниз/вверх только верхнюю границу массива. Изменение нижней границы вызовет ошибку  
 
По-английски данное условие звучит так:  
 
when you use Preserve, you can change the size of the array only by changing the upper bound; changing the lower bound causes an error.  
 
Если у нас массив двумерный, например  
 
Redim myArray (1 to 10, 1 to 3)  
 
то через ReDim Preserve можно будет менять только индекс 3 (т.е. верхний индекс второй размерности) на что-то другое, а другие индексы менять уже нельзя. Т.е. вы не можете изменить 10 на 15  
 
' так сработает  
Redim myArray (1 to 10, 1 to 3)  
ReDim Preserve myArray (1 to 10, 1 to 7)  
 
'а так нет  
Redim myArray (1 to 10, 1 to 3)  
ReDim Preserve myArray (1 to 15, 1 to 3)  
 
 
P.S. Пример с листом Excel это так для "умственного" восприятия. Так же можно выразиться, что двумерный массивы - это матрица. Но мне кажется, что это сложнее понять.  
 
 
Павел
 
УУУ, как всё сложно:)  
 
Правильно ли я понимаю, что той гибкости в работе с диапазонами как на рабочем листе массивы нам не представляют, и обращение к диапазону будет далеко не таким же прозрачным?  
Тогда оставлю эту затею пока, боюсь разбросаюсь.  
А жаль, сейчас данные с листа в массив забираю перебором (пользуясь полученными знаниями в той теме, где Вы с Nerv-ом мне очень помогли), но иногда нужно перебрать строки целиком и перебор выглядит как то не очень рационально.
 
Тему прошел "по диагонали", может, это упоминалось раньше.  
Небольшое предостережение, недавно сам из-за неопытности напоролся.  
Массив, заданный как M(a To b) формирует массив строки, но не столбца. Если задать M(a To b;1), тогда a To b - строки.  
 
Еще момент, на котором время тратил, пытаясь разобраться, почему  созданный массив на лист  выгружается на столбец правее:  
M(a;1) - это не первый столбец, второй. Первый "0" (Option Base не объявлен).  
 
Простые вещи, но новички ошибаются.
 
Пока отвечал HUGO, получил ещё 2 ответа:)  
 
Во общем решил, что не буду впереди паровоза бежать, понял что всё это сложновато пока для восприятия.  
 
Все спасибо за разъяснения.
 
VDM, на самом деле с массивом работать проще, чем с листом.  
И за счёт скорости работы с массивом - при нужде его переопределить можно просто создав новый массив нужного размера и переложить данные в него.  
Но конечно если это делать часто в цикле - это очень не оптимально.  
По правде, у меня не было такой нужды - переопределять многомерные массивы. Всегда иначе можно выкрутиться.  
Но если бы можно было "удлинять" массив вниз - это было бы очень неплохо :)
 
{quote}{login=VDM}{date=23.01.2012 12:04}{thema=}{post}УУУ, как всё сложно:){/post}{/quote}  
зря вы так про массивы, если ими умело пользоваться, все будет работать гораздо быстрее и качественнее. Сама по себе скорость перебора массива минимальна, основное время отнимают операции сравнения , преобразования и т.д. внутри цикла.  
Есть разные способы и хитрости как увеличить скорость,например при поиске уникальных использовать словари, индексировать массив словарем и т.д. , все зависит от конкретной ситуации.
Спасибо
 
VDM,    
 
Смотрите как удобно работать с данными на листе через массивы  
 
 
Sub Test()  
   Dim myArr(), i As Long, n As Long  
     
   'допустим есть какие-то данные на листе  
   Range("A1:D1") = Array("1", "2", "3", "4")  
   Range("A2:D2") = Array("5", "6", "7", "8")  
   Range("A3:D3") = Array("9", "10", "11", "12")  
     
   'берём их в массив (массив получается двумерным)  
   myArr() = Range("A1:D3").Value  
     
   'в цикле умножаем каждое значение столбца на 2  
   For n = 1 To UBound(myArr, 1) 'цикл по строкам  
       For i = 1 To UBound(myArr, 2)  'цикл по столбцам  
           myArr(n, i) = myArr(n, i) * 2  
       Next i  
   Next n  
     
   'выгружаем наши новые данные обратно на лист  
   Range("F1").Resize(UBound(myArr, 1), UBound(myArr, 2)) = myArr  
End Sub  
 
Данный метод - намного быстрее, чем обрабатывать каждую ячейку на листе.  
 
Т.е. мы сперва берём данные с листа Excel в массив, обрабатываем их и обратно выгружаем на лист. Это быстрее, чем обращение к ячейкам листа
 
Паш есть способ чуть проще :) для данного примера, но ты прав на все сто%%%%%%%  
[a1:d1] = [a1:d1* 2]
Спасибо
 
Вот нашёл пример кода (не записал, где применял) - тут нужно было удалить строки с значениями, присутствующими на другом листе (по первым столбцам):  
 
Sub tt()  
   Dim tm: tm = Timer  
   Dim r As Range, a(), b(), i&  
   Application.ScreenUpdating = 0  
 
   Set r = Range([a1], [a65536].End(xlUp))
   a = r.Value  
 
   With Sheets("что искать")  
       b = .Range(.[a1], .[a65536].End(xlUp)).Value
   End With  
 
   With CreateObject("Scripting.Dictionary")  
       .CompareMode = 1  
       For i = 1 To UBound(b)  
           .Item(b(i, 1)) = 1  
       Next  
 
       For i = 1 To UBound(a)  
           If .exists(a(i, 1)) Then a(i, 1) = "d"  
       Next  
 
       r.Value = a  
       r.SpecialCells(xlCellTypeConstants, 2).EntireRow.Delete  
 
   End With  
   Debug.Print Timer - tm  
End Sub  
 
Кода мало, работает почти моментально.  
 
Это были только числа, т.е. в удаляемые строки пишем текст, потом эти строки удаляем.
 
Нет, Вы меня не так поняли - я не собираюсь отказываться от массивов).  
У меня уже сейчас вся отчётность на них построена.  
Просто не буду пытаться применить то, чего не знаю.    
Будем учиться постепенно.  
 
55557
 
{quote}{login=Hugo}{date=22.01.2012 02:59}{thema=}{post}Если массив типа Variant - т.е. как всюду в примерах, без явного указания типа массива, то в массиве могут храниться и числа, и даты, и строки. Т.е. что есть на листе - то и будет в массиве.{/post}{/quote}  
это никаким образом не нарушает формулировку - в этом случае все элементы будут однотипно типа вариант :)
Живи и дай жить..
 
{quote}{login=vikttur}{date=23.01.2012 12:07}{thema=}{post}Массив, заданный как M(a To b) формирует массив строки, но не столбца. Если задать M(a To b;1), тогда a To b - строки.{/post}{/quote}  
Чего? О_о Нет вообще таких понятий как "массив строки" или "массив столбца". Существуют одномерные, многомерные и массивы массивов. Также массивы подразделяются на статические и динамические. Директива Option Base [Число] переопределяет нижнюю границу массива. По умолчанию нижней границей массива считается 0.
 
это M(1 To 1) - одномерный массив  
это M(1 To 1, 1 To 1) - двумерный массив  
 
Поскольку таблица excel представлена двумя измерениями, на лист можно выгрузить (через resize) только двумерный массив (насколько мне известно).
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


https://github.com/nervgh
 
Чего? :)  
 
Sub tt()  
Dim arr  
arr = Array(1, 2, 3)  
[a1].Resize(, UBound(arr) + 1) = arr
End Sub
Страницы: 1 2 След.
Читают тему
Наверх