动态数组公式,允许目标表扩展

时间:2018-03-10 03:45:26

标签: excel vba excel-vba excel-formula array-formulas

我有一个工作表,我将数据从Table1复制到Table2。

将数据复制粘贴到位于Table1下面的Table2后,我选择Table2第一列中的第一个单元格,然后按 Ctrl + Shift + 向下以选择下一个使用过的单元格。最后,我应用了一个串联数组公式,它为Table1中相关单元格的值添加了一个后缀。我已将这些Table2步骤记录为宏。

为了演示,Table1看起来像这样:

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

这是我在表2的A列中使用的公式:

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

这是将其应用于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


现在,当我向Table1添加新条目时,例如在单元格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 

运行录制的宏后,而不是使用新范围A2:A9,它使用之前记录的范围(A2:A7),导致#N/A错误,如表2a所示:

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

这是因为在数组公式中,范围不是动态的,而是固定的。

所以,我想要一个在Table1中添加或删除新条目时自动调整范围的公式。在应用数组公式之前,类似于我在录制的宏中选择Table2的A列中的所有单元格的东西:

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

我正在考虑以下内容,其中我提供了Table1的起始单元格,并且自动计算了数据的最后一个单元格的范围:

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

我想要一个公式解决方案,我可以应用于所有细胞。我不想定义变量等来做到这一点。

2 个答案:

答案 0 :(得分:2)

答案很简单:

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

请注意,您必须将原始数组公式中的每个引号"转换为双引号""

解决方案的技巧是计算范围的最后一个单元格的地址,并用此地址替换A6。这必须在外部字符串中完成,并使用字符串连接运算符&添加到字符串中。

但是,Application.GotoSelectSelection是不必要的。

因此你真的应该使用:

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

使用With对此进行编码的另一种方法是:

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

最后,一个“适当的”VBA解决方案(你明确表示你不想要的那个):

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

请注意,使用此最后一个解决方案,不再需要手动将数据从Table1预复制到Table2。

<强>附录:

刚才意识到你要求的是一个“纯粹的”公式解决方案。如果这就是你所追求的,那么这个公式就可以了:

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

请记住在转换它以便在VBA中使用时双引所有单引号。由此产生的VBA看起来像这样:

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

X-Solution (见What is the XY problem?

如果你只是使用普通公式而不是数组公式,你也意识到你实际上并不需要复杂的动态公式。

只需选择表2的列A,然后在单元格A25中输入以下公式。按 Ctrl + Enter 将其作为所有选定单元格中的常规公式输入。

=CONCATENATE(A2," - A")

VBA代码是:

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

当您在Table1中添加或删除行时,此公式将自动调整。

当然,我建议使用“正确”的全自动VBA代码,不需要手动预复制:

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

最后:

在查看之前的问题以及此问题中提供的数据后,列B - E的解决方案同样简单。所有这些列都使用相同的公式,使用 Ctrl + Enter 输入到单元格B25

正常公式:

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

等效VBA:

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

“正确”全自动VBA:

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

请注意,我通过直接使用数字而不是数字作为字符串,然后使用VALUE()将数字转换为数字来简化公式。

答案 1 :(得分:0)

您需要公式中的范围根据A列中的文本值动态扩展。

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

为了使数字条目均匀化,它们应使用相同的匹配公式来确定终止行。对于B列,

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