简体   繁体   中英

Excel VBA - use array for function (3 variables)

In Excel VBA, I have a function for y with input of 3 variables (a, b, c). What I would like to do is to use VBA to apply this function automatically to a range of cells (combinations of a, b and c as listed in the worksheet).

The way I have my data set up:

  b   1  1  1  1  1  2  2  2  2  3  3  3  4  4  etc.
  c   2  3  4  5  6  3  4  5  6  4  5  6  5  6  etc.

a  
1     .  .  .  .  .  .  .  .  .  .  .  .  .  .
2     .  .  .  .  .  .  .  .  .  .  .  .  .  .
3     .  .  .  .  .  .  .  .  .  .  .  .  .  .
4     .  .  .  .  .  .  .  .  .  .  .  .  .  .
etc.

The 'dots' are where the results of function(a,b,c) should end up (eg, top left dot should be result of "function(1,1,2)"). Of note, within a column the same paired values of b and c should be used (so within the same column, only 'a' varies while b and c remain constant).

A previous version of this function only had 2 variables as input (a and b, set up in the same way as the data above), and I used a 2D-array (values of 'a' on rows vertically, values of 'b' on columns horizontally) to apply the function on all combinations of a and b using the following code:

Sub applyfunction()
Dim ws As Worksheet
Dim arr_ab()
Dim a, b, i As Long, j As Long

For Each ws In Worksheets
   If ws.Name Like "Util*" Then
       With ws
           a = .Range("B5:B244").Value
           b = .Range("C2:CG2").Value
           ReDim arr_ab(1 To UBound(a), 1 To UBound(b, 2))
           For i = LBound(arr_ab) To UBound(arr_ab)
              For j = LBound(arr_ab, 2) To UBound(arr_ab, 2)
                arr_ab(a, b) = "=function(" & a(i, 1) & ", " & b(1, j) & ")"
              Next j
           Next i
           .Range("C5:CG244").Value = arr_ab()
       End With
   End If
Next ws

End Sub

However, now that I have added a third variable (c) to the function, I want to use function(a,b,c). I have some trouble getting it to work like I did when I only had 2 variables. Is there a way to still use an array for this?

Thanks in advance for any help.

Edit: I want to use the values (not the references) of a,b,c in the function

Option Explicit
Sub ApplyFunction()

Dim Arng As Range: Set Arng = Application.Range("A4:A8")
Dim AVal As Integer
Dim ACell As Range
Dim ARow As Integer

Dim Brng As Range: Set Brng = Application.Range("C1:G1")
Dim BVal As Integer
Dim BCell As Range
Dim BCol As Integer
Dim BRow As Integer

Dim CVal As Integer


For Each ACell In Arng
  AVal = ACell.Value
  ARow = ACell.Row
  For Each BCell In Brng
    BVal = BCell.Value
    BCol = BCell.Column
    BRow = BCell.Row
    CVal = Cells(BRow + 1, BCol)
    Cells(ARow, BCol) = ABC(AVal, BVal, CVal)
  Next
Next


End Sub

Function ABC(A As Integer, B As Integer, C As Integer) As Integer
   ABC = A * B * C
End Function

I'm not sure if this is what you want or not. The problem you have with using three elements in the array is you lose the mapping from a 2 dimensional result set to a three dimensional array. So you would have to do something different when you want to transfer the results on to your work sheet ie not just plot the contents of the array. The short answer rot your question though is yes if can be done you could add many dimensions but it would get less and less efficient and more clumsy in mapping it to a two dimensional result set. I haven't recreated all your code with mine above but I have included enough to show you another way of doing it. I'm not checking what sheet I'm on or fully referencing cells etc but put it in a sheet and it'll do what I think you want then modify to attack the right sheets etc..

Use Application.Transpose() to deal with 1D array, this makes things simpler:

Sub applyfunction()
    Dim ws As Worksheet
    Dim a As Variant, b As Variant, c As Variant
    Dim i As Long, j As Long

    For Each ws In Worksheets
        If ws.name Like "Util*" Then
            With ws
                a = Application.Transpose(.Range("B5", Cells(.Rows.Count, "B").End(xlUp)).Value)
                b = Application.Transpose(Application.Transpose(.Range("C2", .Cells(2, .Columns.Count).End(xlToLeft)).Value))
                c = Application.Transpose(Application.Transpose(.Range("C3").Resize(, UBound(b)).Value))
                ReDim abc(1 To UBound(a), 1 To UBound(b))
                For i = LBound(a) To UBound(a)
                    For j = LBound(b) To UBound(b)
                        abc(i, j) = "=MyFunction(" & a(i) & ", " & b(j) & ", " & c(j) & ")"
                    Next j
                Next i
                .Range("C5").Resize(UBound(a), UBound(b)).Value = abc()
            End With
        End If
    Next
End Sub

While you may keep b and c in a 2D array to shorten the code a little:

Sub applyfunction()
    Dim ws As Worksheet
    Dim a As Variant, bc As Variant
    Dim i As Long, j As Long

    For Each ws In Worksheets
        If ws.name Like "Util*" Then
            With ws
                a = Application.Transpose(.Range("B5", Cells(.Rows.Count, "B").End(xlUp)).Value)
                bc = .Range("C2", .Cells(2, .Columns.Count).End(xlToLeft)).Resize(2).Value
                ReDim abc(1 To UBound(a), 1 To UBound(bc, 2))
                For i = LBound(a) To UBound(a)
                    For j = LBound(bc, 2) To UBound(bc, 2)
                        abc(i, j) = "=MyFunction(" & a(i) & ", " & bc(1, j) & ", " & bc(2, j) & ")"
                    Next
                Next
                .Range("C5").Resize(UBound(a), UBound(bc, 2)).Value = abc()
            End With
        End If
    Next
End Sub

NOTE: I used "MyFunction" instead of "function" to make my test run. Change "MyFunction" to your actual function name

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM