TOP
VBA-Урок 13.3. Використання масивів (Arrays) (Вправи)
Щоби попрактикуватись у використанні масивів, ми створимо нашу власну версію макроса, яку ми використовували для демонстрації переваги масивів у швидкості, крок за кроком...
Далі є початкова точка цієї вправи (ви побачите, що набір даних був зменшений до 1000 рядків):
Тут ви можете завантажити Excel файл з прикладом: arrays_exercise.xls
Ціль вправи: процедура повинна обробляти дані в наборі даних за допомогою циклу і порахувати кількість відповідей "ТАК" або "НІ" для кожного року і для кожного номера клієнта (або "ТАК" або "НІ", залежно від вибору користувача) і ввести цю кількість у вказану комірку робочому аркуші.
Завершіть наступний макрос, щоби зберегти дані з робочого аркуша «DS» в масив:
- Sub actualize()
- Dim last_row As Integer
-
-
-
-
-
- Dim array_db()
-
-
- End Sub
Sub actualize()
Dim last_row As Integer
'Останній рядок набору даних
'...
'Збереження набору даних в динамічному масиві
Dim array_db()
'...
End Sub
Ось один з прикладів вирішення:
- Sub actualize()
- Dim last_row As Integer
-
-
- last_row = Sheets("DS").Range("A1").End(xlDown).Row
-
-
- Dim array_db()
- ReDim array_db(last_row - 2, 2)
-
- For row_number = 2 To last_row
- array_db(row_number - 2, 0) = Sheets("DS").Range("A" & row_number)
- array_db(row_number - 2, 1) = Sheets("DS").Range("B" & row_number)
- array_db(row_number - 2, 2) = Sheets("DS").Range("C" & row_number)
- Next
- End Sub
Sub actualize()
Dim last_row As Integer
'Останній рядок бази даних
last_row = Sheets("DS").Range("A1").End(xlDown).Row
'Збереження набору даних в динамічному масиві
Dim array_db()
ReDim array_db(last_row - 2, 2)
For row_number = 2 To last_row
array_db(row_number - 2, 0) = Sheets("DS").Range("A" & row_number)
array_db(row_number - 2, 1) = Sheets("DS").Range("B" & row_number)
array_db(row_number - 2, 2) = Sheets("DS").Range("C" & row_number)
Next
End Sub
Це в основному повторює те, що ми робили на попередньому уроці...
Але зараз нам потрібно змінити наш макрос додаванням наступних дій:
Визначити вибір користувача ("ТАК" чи "НІ");
Порахувати кількість відповідей "ТАК" чи "НІ" в наборі даних, для того щоби визначити розмір масиву (Redim);
Зберігаємо тільки ті рядки з набору даних, що містять відповіді "ТАК" чи "НІ" в масиві (це означає, що не потрібно зберігати дані з третього стовпця).
Ось один з прикладів вирішення:
- Sub actualize()
- Dim last_row As Integer, search_value As String, insert_row As Integer, value_yes_no As String, rows_number As Integer
-
-
- last_row = Sheets("DS").Range("A1").End(xlDown).Row
-
-
- If Sheets("RES").OptionButton_yes.Value = True Then
- search_value = "YES"
- Else
- search_value = "NO"
- End If
-
-
- rows_number = WorksheetFunction.CountIf(Sheets("DS").Range("C2:C" & last_row), search_value)
-
-
- Dim array_db()
- ReDim array_db(rows_number - 1, 1)
-
- insert_row = 0
-
- For row_number = 2 To last_row
- value_yes_no = Sheets("DS").Range("C" & row_number)
-
- If value_yes_no = search_value Then
- array_db(insert_row, 0) = Sheets("DS").Range("A" & row_number)
- array_db(insert_row, 1) = Sheets("DS").Range("B" & row_number)
- insert_row = insert_row + 1
- End If
- Next
- End Sub
Sub actualize()
Dim last_row As Integer, search_value As String, insert_row As Integer, value_yes_no As String, rows_number As Integer
'Останній рядок бази даних
last_row = Sheets("DS").Range("A1").End(xlDown).Row
'Пошук значення (YES чи NO)
If Sheets("RES").OptionButton_yes.Value = True Then
search_value = "YES"
Else
search_value = "NO"
End If
'Кількість відповідей YES чи NO
rows_number = WorksheetFunction.CountIf(Sheets("DS").Range("C2:C" & last_row), search_value)
'Збереження набору даних в масив
Dim array_db()
ReDim array_db(rows_number - 1, 1)
insert_row = 0
For row_number = 2 To last_row
value_yes_no = Sheets("DS").Range("C" & row_number)
If value_yes_no = search_value Then
array_db(insert_row, 0) = Sheets("DS").Range("A" & row_number)
array_db(insert_row, 1) = Sheets("DS").Range("B" & row_number)
insert_row = insert_row + 1
End If
Next
End Sub
Пошук вибором користувача визначається на початку процедури наступним кодом:
-
- If Sheets("RES").OptionButton_yes.Value = True Then
- search_value = "YES"
- Else
- search_value = "NO"
- End If
'Пошук значення (YES чи NO)
If Sheets("RES").OptionButton_yes.Value = True Then
search_value = "YES"
Else
search_value = "NO"
End If
Ми використаємо функцію CountIF, щоби визначити кількість відповідей "ТАК" чи "НІ":
-
- rows_number = WorksheetFunction.CountIf(Sheets("DS").Range("C2:C" & last_row), search_value)
'Кількість відповідей YES чи NO
rows_number = WorksheetFunction.CountIf(Sheets("DS").Range("C2:C" & last_row), search_value)
Розмір масиву був змінений, щоби відповідати кількості відповідей "ТАК" чи "НІ" і зменшити до двох стовпців:
- ReDim array_db(rows_number - 1, 1)
ReDim array_db(rows_number - 1, 1)
Тепер ці дані будуть збережені в масиві, коли його третій стовпець відповідає вибору користувача:
-
- insert_row = 0
-
-
- For row_number = 2 To last_row
-
- value_yes_no = Sheets("DS").Range("C" & row_number)
-
-
- If value_yes_no = search_value Then
-
- array_db(insert_row, 0) = Sheets("DS").Range("A" & row_number)
-
- array_db(insert_row, 1) = Sheets("DS").Range("B" & row_number)
-
- insert_row = insert_row + 1
- End If
- Next
'Вставлення номеру в масив
insert_row = 0
'Обробка набору даних
For row_number = 2 To last_row
'Значення стовпця C (YES чи NO)
value_yes_no = Sheets("DS").Range("C" & row_number)
'Якщо значення відповідає вибору користувача, рядок зберігається в масиві
If value_yes_no = search_value Then
'Збереження значення в стовпець A
array_db(insert_row, 0) = Sheets("DS").Range("A" & row_number)
'Збереження значення в стовпець B
array_db(insert_row, 1) = Sheets("DS").Range("B" & row_number)
'Один рядок був збережений => номер вставлення в масиві збільшується на 1
insert_row = insert_row + 1
End If
Next
Наш масив містить лише ті дані, які нас цікавлять.
Все, що ам залишилось зробити, це:
Обробити кожен елемент таблиці на робочому аркуші "RES", використовючи 2 цикла (така сама ідея, як і у вправі з шахматною дошкою);
Вставити загальну кількість входжень на цьому аркуші для кожного року в розрізі кожного номера клієнта для кожної комірки.
Ось один з прикладів вирішення:
-
- For no_years = 2011 To 2026
- For no_client = 1 To 30
- counter = 0
-
- For i = 0 To UBound(array_db)
- If Year(array_db(i, 0)) = no_years And array_db(i, 1) = no_client Then
- counter = counter + 1
- End If
- Next
-
- Cells(no_years - 2009, no_client + 1) = counter
- Next
- Next
'Кількість відповідей "YES"/"NO"
For no_years = 2011 To 2026
For no_client = 1 To 30
counter = 0
For i = 0 To UBound(array_db)
If Year(array_db(i, 0)) = no_years And array_db(i, 1) = no_client Then
counter = counter + 1
End If
Next
Cells(no_years - 2009, no_client + 1) = counter
Next
Next
Вирішенн задачі з коментарями, що пояснюють це в деталях:
-
- For no_years = 2011 To 2026
-
-
- For no_client = 1 To 30
-
- counter = 0
-
-
- For i = 0 To UBound(array_db)
-
- If Year(array_db(i, 0)) = no_years And array_db(i, 1) = no_client Then
-
- counter = counter + 1
- End If
- Next
-
-
- Cells(no_years - 2009, no_client + 1) = counter
- Next
- Next
'Цикл для кожного рядка
For no_years = 2011 To 2026
'Цикл для кожного стовпця
For no_client = 1 To 30
'Скидання лічильника
counter = 0
'Обробка масиву
For i = 0 To UBound(array_db)
'Перевірка, що рядок в таблиці відповідає року та номеру клієнта
If Year(array_db(i, 0)) = no_years And array_db(i, 1) = no_client Then
'Якщо рік та номер клієнта відповідає, лічильник збільшується на 1
counter = counter + 1
End If
Next
'Після обробки масиву, підсумок вводиться у відповідну комірку
Cells(no_years - 2009, no_client + 1) = counter
Next
Next
І накінець, код усього нашого макроса:
- Sub actualize()
- Dim last_row As Integer, search_value As String, insert_row As Integer, value_yes_no As String, rows_number As Integer, counter As Integer
-
-
- Range("B2:AE17").ClearContents
-
-
- last_row = Sheets("DS").Range("A1").End(xlDown).Row
-
-
- If Sheets("RES").OptionButton_yes.Value = True Then
- search_value = "YES"
- Else
- search_value = "NO"
- End If
-
-
- rows_number = WorksheetFunction.CountIf(Sheets("DS").Range("C2:C" & last_row), search_value)
-
-
- Dim array_db()
- ReDim array_db(rows_number - 1, 1)
-
- insert_row = 0
-
- For row_number = 2 To last_row
- value_yes_no = Sheets("DS").Range("C" & row_number)
-
- If value_yes_no = search_value Then
- array_db(insert_row, 0) = Sheets("DS").Range("A" & row_number)
- array_db(insert_row, 1) = Sheets("DS").Range("B" & row_number)
- insert_row = insert_row + 1
- End If
- Next
-
-
- For no_years = 2011 To 2026
- For no_client = 1 To 30
- counter = 0
-
- For i = 0 To UBound(array_db)
- If Year(array_db(i, 0)) = no_years And array_db(i, 1) = no_client Then
- counter = counter + 1
- End If
- Next
- Cells(no_years - 2009, no_client + 1) = counter
- Next
- Next
- End Sub
Sub actualize()
Dim last_row As Integer, search_value As String, insert_row As Integer, value_yes_no As String, rows_number As Integer, counter As Integer
'Видалення вмісту
Range("B2:AE17").ClearContents
'Останній рядок в наборі даних
last_row = Sheets("DS").Range("A1").End(xlDown).Row
'Пошук значення (YES чи NO)
If Sheets("RES").OptionButton_yes.Value = True Then
search_value = "YES"
Else
search_value = "NO"
End If
'Кількість відповідей YES чи NO
rows_number = WorksheetFunction.CountIf(Sheets("DS").Range("C2:C" & last_row), search_value)
'Збереження значень в масив
Dim array_db()
ReDim array_db(rows_number - 1, 1)
insert_row = 0
For row_number = 2 To last_row
value_yes_no = Sheets("DS").Range("C" & row_number)
If value_yes_no = search_value Then
array_db(insert_row, 0) = Sheets("DS").Range("A" & row_number)
array_db(insert_row, 1) = Sheets("DS").Range("B" & row_number)
insert_row = insert_row + 1
End If
Next
'Підрахунок відповідей YES чи NO
For no_years = 2011 To 2026
For no_client = 1 To 30
counter = 0
For i = 0 To UBound(array_db)
If Year(array_db(i, 0)) = no_years And array_db(i, 1) = no_client Then
counter = counter + 1
End If
Next
Cells(no_years - 2009, no_client + 1) = counter
Next
Next
End Sub
Тут ви можете завантажити Excel файл з прикладом: arrays_exercise_completed.xls