我有一组三个公式,它们将交换机 VLAN 分配输出中的端口列表转换为溢出到下方单元格中的数组,我想将它们合并为一个公式(不太了解 VBA,所以我想将其保留在现有公式中)。下面是它的工作原理。
A3 中的示例数据: A1-A10,B20-B22,C12,D15-D17
(请注意,文本字符串可能同时包含普通空格和 CHAR(160),因此下面是 TRIM + SUBSTITUTE)
此公式只是将逗号分隔的值拆分成单独的单元格,但同时也删除了前导空格。
A5=TRANSPOSE(TEXTSPLIT(TRIM(SUBSTITUTE(A3,CHAR(160),)),","))
结果:
A1-A10
B20-B22
C12
D15-D17
此外,我还开发了以下灾难来打印上述公式生成的每个单元中描述的所有端口:
=IF(A5="","",TRANSPOSE(IF(ISNUMBER(FIND("-",A5)),LEFT(A5)&SEQUENCE(RIGHT(A5,LEN(A5)-FIND("-",A5)-1)-MID(A5,2,FIND("-",A5)-2)+1,1,MID(A5,2,FIND("-",A5)-2)),A5)))
如果确保空源单元格产生空白结果单元格,则 TRANSPOSE 将列范围转换为行范围,从而允许公式向右溢出 IF(ISNUMBER(FIND("-"... 通过搜索连字符/破折号来检查单元格是否包含范围,否则返回 A5 本身 LEFT(A5)&SEQUENCE(... 从单元格值的开头获取字母并根据第二个和第一个端口号之间的差异加 1(17-15=2,2+1=3)生成端口序列。
此公式(复制了几行以确保涵盖非常不同的 VLAN 分配)生成一个单独值的数组,如下所示:
A1 A2 A3 A4 A5 A6 A7 A8 A9 A10
B20 B21 B22
C12
D15 D16 D17
然后我使用以下公式将所有值“展平”到单个列中:
=TRANSPOSE(TEXTSPLIT(TEXTJOIN(",",TRUE,AB5:AY20),",",,TRUE))
最终的数组如下所示:
A1
A2
A3
A4
A5
A6
A7
A8
A9
A10
B20
B21
B22
C12
D15
D16
D17
我想将这三个公式结合起来,这样指向示例数据的单个公式就会扩展到上面显示的所有包含的端口 ID 的单个列中。
我该如何组合这些公式来实现这一点,或者如何创建一个公式来更有效地完成相同的任务?
答案1
如果这些地址类似于单元格地址,则使用 UDF 的解决方案似乎要简单得多。考虑这样的代码:
Function ListA(data As String)
Dim rng As Range, i As Long, res() As String ' declare variables
data = Replace(data, Chr(160), vbNullString) ' remove non-breaking spaces
data = Replace(data, "-", ":") ' convert e.g. A1-A10 to A1:A10
ReDim res(1 To Range(data).Count, 1 To 1) ' define structure of
' the array: 1st dimension from 1 to number of cell addresses,
' 2nd dimension is necessary to get a column, not a row
For Each rng In Range(data) ' loop for each cell
i = i + 1 ' increase counter
res(i, 1) = rng.Address(0, 0) ' populate resulting array
' element with a cell address without $
Next rng
ListA = res ' assign the resulting array to the function result
End Function
在工作表中输入
=ListA(A3)
即可获得垂直的地址列表。
答案2
这是我去年针对此类问题开发的通用 lambda 模块。
这是要点的链接,您可以将其导入 Excel Labs 插件中的高级公式环境工具中。或者,您可以在名称管理器中将 LAMBDA 函数创建为名称(尽管这是一个繁琐的过程)。
https://gist.github.com/ncalm/ef7ed953571eec1475c291948aa2dbc3
根据 SU 规则,以下是代码:
/*
array is a column of stuff to which we want to apply element function
row_function is some function that produces an array with a fixed number of columns
the column count produced by row_function must be identical regardless of input
stack_function is one of V or H
If you're unsure how these work or why we would use them, please review these videos:
https://youtu.be/04jOeiMypXw
https://youtu.be/wEBLT9QfQRw
*/
V = LAMBDA(one, two, VSTACK(one, two));
H = LAMBDA(one, two, HSTACK(one, two));
STACKER = LAMBDA([stack_function],
LAMBDA(row_function,
LAMBDA(array,
LET(
_stack_function, IF(ISOMITTED(stack_function), V, stack_function),
seq, SEQUENCE(ROWS(array)),
firstrow, row_function(INDEX(array,1,)),
reducer, REDUCE(
firstrow,
DROP(seq, 1),
LAMBDA(acc, curr,
LET(thisrow, INDEX(array,curr,), _stack_function(acc, row_function(thisrow)))
)
),
reducer
)
)
)
);
VSTACKER = STACKER(V);
HSTACKER = STACKER(H);
使用方法如下:
创建一个处理形式为{from}-{to}的单行的函数,例如:
CreateVLANRange=LAMBDA(x,
LET(
parts, TEXTSPLIT(x, "-"),
fromText, INDEX(parts,1,1),
toText, INDEX(parts,1,COLUMNS(parts)),
getNum, LAMBDA(x, MID(x,2,LEN(x))),
fromNum, getNum(fromText),
LEFT(fromText)&SEQUENCE(getNum(toText)-fromNum+1,,fromNum)
)
);
然后,假设您已将堆栈器代码导入到名为 STACKER 的模块中:
您可以使用此公式将输入字符串处理为单列端口:
=LET(input, A3,
arrayToProcess, TRIM(TEXTSPLIT(SUBSTITUTE(input,CHAR(160),),,",")),
STACKER.VSTACKER(CreateVLANRange)(arrayToProcess))
这可能看起来非常冗长,但定义行函数并将其传递给 VSTACKER 的过程是我见过的一个常见问题。
欢迎您观看要点中链接的视频,我会回答您对此提出的任何问题。
答案3
这是 DROP/REDUCE/VSTACK 方法的另一个版本,使用一些替代函数和技术来提取必要的变量:
=DROP(REDUCE("", TEXTSPLIT(TRIM(SUBSTITUTE(A3,CHAR(160),)),","), LAMBDA(v,n,
LET(m, REPLACE(TEXTBEFORE(n,"-",,,,n),1,1,),
VSTACK(v, LEFT(n)&SEQUENCE(REPLACE(TEXTAFTER(n,"-",,,,n),1,1,)-m+1,,m))))),1)