Vba передает группу ячеек как диапазон для функции

Я получаю группу ячеек и делаю некоторые вычисления над ними в функции ниже.

Он работает, если я передаю диапазон (с знаком :) в качестве первого параметра, но он терпит неудачу, если я выбираю некоторые ячейки в качестве диапазона (A1, A3, B6, B9). Он просто получает первую ячейку перед запятой в качестве первого параметра. Но я хочу целые ячейки.

Что я могу сделать? (за исключением использования строк для прохождения диапазонов)

Function calculateIt(Sessions As Range, Customers As Range) As Single
    ' calculate them...
End Function

Еще одно: Можно ли передать группу диапазонов в качестве параметра? как?

Ответ 1

Как написано, ваша функция принимает только два диапазона в качестве аргументов.

Чтобы разрешить использование переменной числа диапазонов в функции, вам нужно объявить массив вариантов ParamArray в списке аргументов. Затем вы можете обрабатывать каждый из диапазонов в массиве по очереди.

Например,

Function myAdd(Arg1 As Range, ParamArray Args2() As Variant) As Double
    Dim elem As Variant
    Dim i As Long
    For Each elem In Arg1
        myAdd = myAdd + elem.Value
    Next elem
    For i = LBound(Args2) To UBound(Args2)
        For Each elem In Args2(i)
            myAdd = myAdd + elem.Value
        Next elem
    Next i
End Function

Затем эту функцию можно использовать на листе для добавления нескольких диапазонов.

myAdd usage

Для вашей функции возникает вопрос, какой из диапазонов (или ячеек), которые могут передаваться функции, это "Сеансы" и "Клиенты".

Самый простой случай - если вы решили, что первый диапазон - это сеансы, а любые последующие диапазоны - это клиенты.

Function calculateIt(Sessions As Range, ParamArray Customers() As Variant) As Double
    'This function accepts a single Sessions range and one or more Customers
    'ranges
    Dim i As Long
    Dim sessElem As Variant
    Dim custElem As Variant
    For Each sessElem In Sessions
        'do something with sessElem.Value, the value of each
        'cell in the single range Sessions
        Debug.Print "sessElem: " & sessElem.Value
    Next sessElem
    'loop through each of the one or more ranges in Customers()
    For i = LBound(Customers) To UBound(Customers)
        'loop through the cells in the range Customers(i)
        For Each custElem In Customers(i)
            'do something with custElem.Value, the value of
            'each cell in the range Customers(i)
            Debug.Print "custElem: " & custElem.Value
         Next custElem
    Next i
End Function

Если вы хотите включить любое количество диапазонов сеансов и любое количество диапазонов клиентов, вам нужно будет включить аргумент, который будет указывать функции, чтобы он мог отделять диапазоны сеансов от диапазона Customers.

Этот аргумент может быть настроен как первый, числовой аргумент функции, который будет определять, сколько из следующих аргументов являются диапазонами сеансов, при этом оставшиеся аргументы неявно являются диапазонами клиентов. Тогда сигнатурой функции будет:

Function calculateIt(numOfSessionRanges, ParamAray Args() As Variant)

Или это может быть аргумент "guard", который отделяет диапазоны сеансов от диапазонов Customers. Затем ваш код должен будет проверить каждый аргумент, чтобы убедиться, что это был защитник. Функция будет выглядеть так:

Function calculateIt(ParamArray Args() As Variant)

Возможно, с вызовом что-то вроде:

calculateIt(sessRange1,sessRange2,...,"|",custRange1,custRange2,...)

Программная логика может быть в следующем порядке:

Function calculateIt(ParamArray Args() As Variant) As Double
   ...
   'loop through Args
   IsSessionArg = True
   For i = lbound(Args) to UBound(Args)
       'only need to check for the type of the argument
       If TypeName(Args(i)) = "String" Then
          IsSessionArg = False
       ElseIf IsSessionArg Then
          'process Args(i) as Session range
       Else
          'process Args(i) as Customer range
       End if
   Next i
   calculateIt = <somevalue>
End Function

Ответ 2

Существует еще один способ передать несколько диапазонов функции, которая, как мне кажется, намного удобнее для пользователя. Когда вы вызываете свою функцию в электронной таблице, вы переносите каждый набор диапазонов в скобки, например: calculateIt( (A1,A3), (B6,B9) )

Вышеупомянутый вызов предполагает, что ваши две сессии находятся в A1 и A3, а ваши два клиента находятся в B6 и B9.

Чтобы сделать эту работу, ваша функция должна прокручивать каждый из Areas в диапазонах ввода. Например:

Function calculateIt(Sessions As Range, Customers As Range) As Single

    ' check we passed the same number of areas
    If (Sessions.Areas.Count <> Customers.Areas.Count) Then
        calculateIt = CVErr(xlErrNA)
        Exit Function
    End If

    Dim mySession, myCustomers As Range

    ' run through each area and calculate
    For a = 1 To Sessions.Areas.Count

        Set mySession = Sessions.Areas(a)
        Set myCustomers = Customers.Areas(a)

        ' calculate them...
    Next a

End Function

Хорошо, если у вас есть оба входа в качестве непрерывного диапазона, вы можете вызвать эту функцию так же, как и обычную. calculateIt(A1:A3, B6:B9).

Надеюсь, что помогает:)

Ответ 3

Будучи новичком в vba, я хочу получить от vba глубокие знания о том, как все встроенные функции Excel работают там.

Так что, как и в предыдущем вопросе, я приложил свои основные усилия.

Function multi_add(a As Range, ParamArray b() As Variant) As Double

    Dim ele As Variant

    Dim i As Long

    For Each ele In a
        multi_add = a + ele.Value **- a**
    Next ele

    For i = LBound(b) To UBound(b)
        For Each ele In b(i)
            multi_add = multi_add + ele.Value
        Next ele
    Next i

End Function

- a: Это вычитается для приведенного выше кода, поскольку счетчик удваивается, поэтому при добавлении значений первое значение добавляется дважды.