Home » excel » excel – Dynamic array formula that allows for target table expansion

excel – Dynamic array formula that allows for target table expansion

Posted by: admin April 23, 2020 Leave a comment

Questions:

I have a worksheet where I copy data from Table1 to Table2.

Once I have copy-pasted the data to Table2, which sits below Table1, I select the first cell in the first column of Table2 and press Ctrl+Shift+Down to select down to the last used cell. Finally, I apply a concatenation array formula that adds a suffix to the values of the related cells in Table1. I have recorded these Table2 steps as a macro.

To demonstrate, Table1 looks like this:

Table1

   |  A      B   C   D   E
---+-----------------------
 1 | Name    V1  V3  V3  V4
---+-----------------------
 2 | Wood    10  10  10  10
 3 | wood    28  28  28  28
 4 | tree    30  45  60  68
 5 | plastic 50  50  50  50
 6 | tree    50  50  50  50
 7 | iron    64  75  75  80

This is the formula I use in column A of Table2:

{=concatenate(A2:A7," - A")}

This is the result after applying it to Table2:

Table2

   |  A               B    C    D    E
---+-----------------------------------
25 | Wood - A        25   25   25   25
26 | wood - A        50   50   50   50
27 | tree - A        50   50   100  100
28 | plastic - A     100  100  100  100
29 | tree - A        100  100  100  100
30 | iron - A        100  100  100  100

Now, when I add new entries to Table1, for example in cells A8 & A9:

Table1a

   |  A      B   C   D   E
---+-----------------------
 1 | Name    V1  V3  V3  V4
---+-----------------------
 2 | Wood    10  10  10  10
 3 | wood    28  28  28  28
 4 | tree    30  45  60  68
 5 | plastic 50  50  50  50
 6 | tree    50  50  50  50
 7 | iron    64  75  75  80
 8 | table   20  25  0   30
 9 | plastic 54  35  21  0 

after running the recorded macro, instead of using the new range A2:A9, it’s using the previous recorded range (A2:A7), resulting in the #N/A errors as can be seen in Table2a:

Table2a

   |  A               B    C    D    E
---+-----------------------------------
25 | Wood - A        25   25   25   25
26 | wood - A        50   50   50   50
27 | tree - A        50   50   100  100
28 | plastic - A     100  100  100  100
29 | tree - A        100  100  100  100
30 | iron - A        100  100  100  100
31 | #N/A            #N/A #N/A #N/A #N/A
32 | #N/A            #N/A #N/A #N/A #N/A

This is because in the array formula, the range is not dynamic, but fixed.

So, I would like a formula which auto-adjusts the range when new entries are added or deleted from Table1. Something similar to what I have in the recorded macro which selects all the cells in column A of Table2, before applying the array formula:

Application.Goto Reference:="R25C1"
Range("A25", Range("A25").End(xlDown)).Select

I was thinking of something like the following, where I provide the starting cell of Table1 and the range down to the last cell with data is worked out automatically:

Selection.FormulaArray = "=concatenate(Range("A2",Range("A2").End(xldown)).Select,""- A"")"

I would like a formula solution, that I can apply to all the cells. I don’t want to define variables, etc, to do this.

How to&Answers:

The answer is as simple as:

Selection.FormulaArray = "=concatenate(A2:" & Range("A2").End(xlDown).Address & ","" - A"")"

Note that you have to convert every single quote, ", in the original array formula to double quotes, "".

The trick with the solution is to calculate the address of the last cell of the range, and replace the A6 with this address. This has to be done outside the string, and added to the string by using the string concatenation operator &.


However, the Application.Goto, Select, and Selection are unnecessary.

Thus you really should use:

Range("A25", Range("A25").End(xlDown)).FormulaArray _
= "=concatenate(A2:" & Range("A2").End(xlDown).Address & ","" - A"")"

Another way of coding this, using With, would be:

With Range("A25", Range("A25").End(xlDown))
  .FormulaArray = "=concatenate(A2:" & Range("A2").End(xlDown).Address & ","" - A"")"
End With

Finally, a “proper” VBA solution (the one you specifically said you didn’t want):

With Range("A2").End(xlDown)
  Range("A25", .Offset(25 - 2)).FormulaArray = "=concatenate(A2:" & .Address & ","" - A"")"
End With

Note that with this last solution, there is no longer a requirement to manually pre-copy the data from Table1 to Table2.


ADDENDUM:

Just realised that you were asking for a “pure” formula solution. If that’s all you’re after, then this formula works:

{=CONCATENATE(A2:INDEX(A1:A24,MATCH("*",A1:A24,-1))," - A")}

Just remember to double quote all the single quotes when converting it for use in VBA. The resulting VBA would thus look like this:

Selection.FormulaArray = "=CONCATENATE(A2:INDEX(A1:A24,MATCH(""*"",A1:A24,-1)),"" - A"")"

X-Solution (See What is the XY problem?)

Also just realised that you don’t actually need a complicated dynamic formula if you just use a normal formula instead of an array formula.

Just select column A of Table2 and enter the following formula in cell A25. Press Ctrl+Enter to enter it as normal formula in all the selected cells.

=CONCATENATE(A2," - A")

The VBA code for this is:

Selection.Formula = "=CONCATENATE(A2,"" - A"")"

This formula will automatically adjust as you add or remove rows from Table1.

Of course, I would recommend using the “proper” fully automatic VBA code which doesn’t require manual pre-copying:

Range("A25", Range("A2").End(xlDown).Offset(25 - 2)).Formula = "=CONCATENATE(A2,"" - A"")"

And Finally:

After looking at your previous questions and the supplied data in this one, the solution for columns BE is similarly simple. The same formula is used for all those columns, entered into cell B25 using Ctrl+Enter.

Normal formula:

=IF(B2<25,25,IF(B2<50,50,100))

Equivalent VBA:

Selection.Formula = "=IF(B2<25,25,IF(B2<50,50,100))"

“Proper” fully-auto VBA:

With Range("A2").End(xlDown)
  Range("B25", .Offset(25 - 2, 4)).Formula = "=IF(B2<25,25,IF(B2<50,50,100))"
End With

Note that I have simplified the formula by using numbers directly instead of numbers as strings and then using VALUE() to convert them to numbers.

Answer:

You need a range in the formula that dynamically expands according to the text values in column A.

=concatenate(A2:index(a:a, match("zzz", a:a)), " - A")

In order to homogenize the numeric entries, they should use the same match formula to determine the terminating row. For column B,

b2:index(b:b, match("zzz", a:a))