18c0693f

Пользовательские функции, принимающие сложный объект Range


Известно, что в Excel объект Range может представлять несмежную область и являться объединением нескольких интервалов ячеек. Иначе говоря, один объект Range может задавать несколько массивов рабочего листа. Можно ли такой объект передать пользовательской функции и, если да, как его обрабатывать? Ответ: "можно", хотя соответствующий формальный параметр следует описывать особым образом. Процедуры и функции VBA допускают произвольное число параметров, это достигается за счет того, что один, последний по счету формальный параметр может иметь спецификатор ParamArray. В этом случае данный параметр задает фактически массив параметров с произвольным числом элементов. Именно эта техника и применяется для передачи в пользовательскую функцию сложного объекта Range, представляющего не один, а произвольное число массивов. У такой функции последний параметр должен иметь спецификатор ParamArray и быть массивом типа Variant.

Рассмотрим предыдущую задачу, немного усложнив ее, полагая, что при проверке кандидата на "медианность" используется произвольное число массивов. Вот как выглядит функция, решающая эту задачу:

Пример 9.2.

(html, txt)

Комментируя работу этой функции, отметим:

Демонстрацию использования этой функции начнем с ее вызова в процедуре VBA, которая передает ей целочисленный массив элементов:


Public Sub TestIsMedianaForAll() Const Size = 7 Dim Mas( 1 To Size) As Integer Dim Cand As Integer Dim i As Integer Dim Res As Integer 'Инициализация массива целыми в интервале 1-20 Debug.Print TypeName(Mas) Randomize For i = 1 To Size Mas(i) = Int(Rnd * 21) Next i Cand = Int(Rnd * 21) Res = IsMedianaForAll(Cand, Mas) Debug.Print "Массив:" For i = 1 To Size Debug.Print Mas(i) Next i Debug.Print "Кандидат:", Cand Debug.Print "Результат:", Res End Sub

Приведем результаты выполнения этой процедуры:

Integer() Массив: 9 1 14 11 11 18 0 Кандидат: 12 Результат: -3

А теперь покажем, как эта функция вызывается в формулах рабочего листа Excel На том же рабочем листе, где мы проводили эксперименты с формулами, вызывающими функцию IsMediana, мы записали еще несколько формул, вызывающих функцию IsMedianaForAll. Заметьте, ее аргумент может иметь значительно более сложный вид, чем при вызове функции IsMedina.


Рис. 9.2.  Вызов функции IsMedianaForAll, допускающей сложные объекты Range

Проанализируем четыре сделанных вызова:





Dim Val As Variant For Each Val In Elem If Val > Cand Then Pos = Pos + 1 ElseIf Val < Cand Then Neg = Neg + 1 End If Next Val ElseIf TypeName(Elem) = "Integer()" Then 'Это настоящий массив целых VBA, для которого 'определены функции границ. For i = LBound(Elem) To UBound(Elem) If Elem(i) > Cand Then Pos = Pos + 1 ElseIf Elem(i) < Cand Then Neg = Neg + 1 End If Next i Else MsgBox ("При вызове IsMedianaForAll один из аргументов" _ & "не является массивом или объектом Range!") End If Next Elem IsMedianaForAll = Pos - Neg End Function

Пример 9.2.

Комментируя работу этой функции, отметим:



Демонстрацию использования этой функции начнем с ее вызова в процедуре VBA, которая передает ей целочисленный массив элементов:

Public Sub TestIsMedianaForAll() Const Size = 7 Dim Mas(1 To Size) As Integer Dim Cand As Integer Dim i As Integer Dim Res As Integer 'Инициализация массива целыми в интервале 1-20 Debug.Print TypeName(Mas) Randomize For i = 1 To Size Mas(i) = Int(Rnd * 21) Next i Cand = Int(Rnd * 21) Res = IsMedianaForAll(Cand, Mas) Debug.Print "Массив:" For i = 1 To Size Debug.Print Mas(i) Next i Debug.Print "Кандидат:", Cand Debug.Print "Результат:", Res End Sub

Приведем результаты выполнения этой процедуры: