Как я могу создать UDF в VBA с помощью инструкции If And, используя как числовые, так и текстовые значения?

#excel #vba #user-defined-functions

#excel #vba #определяемые пользователем функции

Вопрос:

У меня есть таблица, состоящая из 3 разных категорий: материк, остров, город; каждая из них имеет 2 разных возможных значения, где им присваивается одно в зависимости от «веса». Если ‘Weight’ <= 2 кг, то наш результат ‘Cost’ равен, например, 1.2 (для материка или 1.3 для острова и т.д.). Если ‘weight’ > 2 кг, нам нужно округлить его до ближайшего целого числа, затем вычислить 0,3 (для материка или 0,9 для острова и т.д.), умноженное на дополнительные целые числа свыше 2 кг. Тогда стоимость будет исходным значением для первых 2 кг, а затем сложите десятичное значение каждой области, умноженное на дополнительные целые числа. Я попытался создать свою собственную функцию для выбора 3 ячеек и выполнения вычисления, поскольку она казалась слишком сложной для линейных функций, заданных из excell.

Но я всегда получаю сообщение об ошибке…

Обратите внимание, что все значения переменных взяты из выбранных пользователем ячеек, а значение Location просто проверяет, какой текст находится внутри ячейки, чтобы присвоить правильные числа для вычисления.

Это то, что у меня есть на данный момент… Есть какие-нибудь советы?

Скриншот из таблицы здесь

 Function TotalCost(ByVal tmx As Integer, ByVal weight As Double, _
                                            ByVal Location As Text)
      Dim b As Integer
      Dim c As Integer
      Dim d As Integer

      d = 0
      c = 0
      f = 0
    
      If Location Like "Mainland" And weight <= 2 Then
          TotalCost = 1.2
      ElseIf Location Like "Mainland" And weight > 2 Then

          weight = Round(weight, 0)
          c = weight - 2

          Do While c > 0
              c = c - 1
              d = d   1
          Loop

          TotalCost = tmx * ((d * 9.55)   1.2)
        
      ElseIf Location Like "City" And weight <= 2 Then

          TotalCost = 1.1
     
      ElseIf Location Like "City" And weight > 2 Then

           weight = Round(weight, 0)
           c = weight - 2

           Do While c > 0
               c = c - 1
               d = d   1
           Loop

           TotalCost= tmx * ((d * 0.55)   1.1)
                    
       ElseIf Location Like "Island" And weight <= 2 Then

           TotalCost = 1.3
     
       ElseIf Location Like "Island" And weight > 2 Then

           weight = Round(weight, 0)
           c = weight - 2
           Do While c > 0
               c = c - 1
               d = d   1
           Loop
           TotalCost= tmx * ((d * 0.7)   1.3)
    
       End If

End Function


  

Комментарии:

1. Это не может работать, поскольку Text это недопустимый тип переменной. Вам нужно String . Попробуйте также объявить возвращаемый тип Double . Function TotalCost(...) as double . Я думаю, что есть более простой способ сделать это, хотя и не уверен на 100%, что вы на самом деле делаете.

2. Пожалуйста, старайтесь правильно расставлять отступы при публикации, иначе ваш код будет трудно просмотреть.

3. Обратите внимание, что в одном из ваших случаев TotalCostSkyWalk нет TotalCost Также ваши Integer типы, вероятно, должны быть Double s

Ответ №1:

Что-то более похожее на это могло бы быть лучше:

 Function TotalCost(ByVal tmx As Integer, ByVal weight As Double, _
                                            ByVal Location As String)
    
    Dim base As Double, mult As Double, tot As Double, wtExtra As Double
    
    Select Case Location
        Case "Mainland"
            base = 1.2
            mult = 9.55
        Case "City"
            base = 1.1
            mult = 0.55
        Case "Island"
            base = 1.3
            mult = 0.7
        Case Else
            TotalCost = "?Location?"
            Exit Function
    End Select
    
    If weight > 2 Then
        'round up to nearest kg and subtract 2
        wtExtra = Application.Ceiling(weight, 1) - 2
        TotalCost = tmx * ((wtExtra * mult)   base)
    Else
        TotalCost = base
    End If
      
End Function
  

Комментарии:

1. Это решение отлично справилось с задачей. Большое вам спасибо за вашу помощь и приношу извинения за мои ошибки новичка, я все еще новичок в VBA и здесь, поэтому я все еще учусь.

Ответ №2:

Вы можете выполнить свои вычисления с помощью относительно простой формулы, но для этого требуется небольшая подготовка, часть которой такая же, какая понадобится и для UDF. Вот формула. Я подробно объясню это ниже.

 =VALUE(INDEX(Rates,1,MATCH($F$2,$B$1:$D$1)) (INDEX(Rates,2,MATCH($F$2,$B$1:$D$1))*(-INT($G$2/-2)-1)))*INT(MAX($H$2,1))
  

Сначала настройка.

  1. Я поместил таблицу, которую вы опубликовали в своем вопросе, в диапазон A1: D3.
  2. Я создал именованный диапазон для чисел, B1: D3, и назвал его Rates
  3. Затем я создал раскрывающийся список проверки в F2, который ссылается на диапазон B1: D1 («Город», «Материк», «Острова»)
  4. Я отметил ячейку G2 для ввода веса
  5. И H2 для ввода количества посылок.

Далее подготовка.

  • [G6] =MATCH(F2,B1: D1) возвращает 1, 2 или 3 в зависимости от того, что выбрано в F2
  • [G7] =(-INT(G2 /-2) -1) возвращает количество доплат за дополнительный вес, например 0 для чего-либо до 2 (кг), 1 для 2.1 -4.0, 2 для 2.1 -6.0 и т.д.
  • [G5] =INT(MAX(H2,1)) Все эти формулы должны быть протестированы по отдельности путем проверки их результатов при изменении F2: H2. (Я это сделал.) Это приводит к базовой формуле.

=INDEX(Rates,1,G6) (INDEX(Rates,2,G6)*G7)

и, поскольку это строка,

 =VALUE(INDEX(Rates,1,G6) (INDEX(Rates,2,G6)*G7))
  

и, чтобы умножить на количество участков,

 =VALUE(INDEX(Rates,1,G6) (INDEX(Rates,2,G6)*G7))*G5
  

Теперь все, что осталось сделать, это заменить G5, G6 и G7 в приведенном выше примере формулами в G5, G6 и G7. Затем добавьте знаки $, чтобы включить копирование формулы, и вы получите результат, предложенный первым выше.

Комментарии:

1. Я хочу, чтобы это была функция в виде надстройки, чтобы я мог использовать ее более гибким способом. Спасибо вам за ваше время, несмотря ни на что!