Как передать результат формулы массива в пользовательскую функцию?

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

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

Вот рассматриваемая функция, она адаптирована из этого решения:

Function BasedLerp(a As Single, b As Single, t As Variant) As Variant
    Dim r() As Single
    Dim i As Integer

    'THIS FUNCTION APPROXIMATES THE SAME SUM OF VALUES AS IF IT WAS A 'Lerp(0,b,t)' FUNCTION, BY ACCOUNTING FOR 'a' BEING NON-ZERO
    
    aVal = (a - (b / 2)) * 2 'The Function works on the [-1 ,1] range, this adjust a [0,1] input
    x = (aVal - b) / 2
    
    If Not (isArray(t)) Then
        BasedLerp = (aVal + ((b - aVal) * t)) - x
    ElseIf TypeOf t Is Excel.Range Then
        ReDim r(1 To t.Cells.Count)
        For i = 1 To t.Cells.Count
            r(i) = (aVal + ((b - aVal) * t.Cells(i).Value)) - x
        Next i

        If t.Rows.Count = 1 Then
            BasedLerp = r
        Else
            BasedLerp = Application.Transpose(r)
        End If
    Else
        ReDim r(LBound(t) To UBound(t))
        For i = LBound(t) To UBound(t)
            r(i) = (aVal + ((b - aVal) * t(i))) - x
        Next i

        BasedLerp = r
    End If

End Function

Я хочу использовать его так:

=BasedLerp([base value];1;(H14:H36/I14:I36))

И выдает #Value ошибки

Если бы я изменил его на

=BasedLerp([base value];1;(H14:H36))

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

Возможно ли это? В настоящее время я предполагаю, что возвращаемое значение (H14:H36/I14:I36) не учитывается в сценарии, но я не могу найти никакой документации о том, каким будет тип возвращаемого значения и его формат.


1
94
2

Ответы:

Решено

Чтобы выявить ошибку, необходим глубокий анализ кода.

Итак, когда функция вызывается с помощью «H14:H36» для t, t становится диапазоном. Расчет выполняется ветвью ElseIf и возвращается вертикальный вектор.

Когда функция вызывается с помощью «H14:H36/I14:I36» для t, Excel вычисляет выражение и t становится двумерным массивом (вертикальным вектором). Вычисление переходит в ветвь Else, и t(i) вызывает ошибку, поскольку t не является одномерным массивом. Исправить это можно таким образом:

    Else
        ReDim r(LBound(t) To UBound(t))
        For i = LBound(t) To UBound(t)
            r(i) = (aVal + ((b - aVal) * t(i, 1))) - x
        Next i

        BasedLerp = Application.Transpose(r)
    End If

У меня мало опыта работы с VBA, но после просмотра вашего вопроса я также задался вопросом об использовании параметра массива. В (ограниченном) тестировании итерация с помощью For Each, кажется, работает - вы можете попробовать, если вы еще этого не сделали:


2024-08-19: Спасибо ротабору за указание на ошибки - я их исправил.


Function BasedLerp2(a As Single, B As Single, t As Variant) As Variant
    Dim r() As Variant
    Dim values As Variant
    Dim i As Integer
    Dim item As Variant

    'THIS FUNCTION APPROXIMATES THE SAME SUM OF VALUES AS IF IT WAS A 'Lerp(0,b,t)' FUNCTION, BY ACCOUNTING FOR 'a' BEING NON-ZERO
    
    aVal = (a - (B / 2)) * 2 'The Function works on the [-1 ,1] range, this adjust a [0,1] input
    x = (aVal - B) / 2
    
    If Not (IsArray(t)) Then
        BasedLerp2 = (aVal + ((B - aVal) * t)) - x
    
    Else
        
        If TypeOf t Is Range Then
            values = t.Cells
        Else
            values = t
        End If
        
        ReDim r(LBound(values) To UBound(values))
        i = LBound(values)
        For Each item In values
            r(i) = (aVal + ((B - aVal) * item)) - x
             i = i + 1
        Next item
        
        If TypeOf t Is Range Then
            If t.Rows.Count = 1 Then
                BasedLerp2 = r
            Else
                BasedLerp2 = Application.Transpose(r)
            End If
        Else
            BasedLerp2 = r
        End If
        
    End If

End Function


Интересные вопросы для изучения