Excel 函数无需 VBA 即可根据值构造数组

问题描述 投票:0回答:5

NB 这个问题涉及一些功能,例如可选的 LAMBDA 参数和 ISOMITTED 函数,这些功能仅在 Beta 通道中可用(在撰写本文时)(更多信息此处


我正在尝试在 Excel LAMBDA 函数中模仿 VBA 的参数数组,所以想要一个函数:

=ARRAY(arg_1, [arg_2], [arg_3], ...)

...返回数组

{arg_1, arg_2, arg_3, ...}
根据传递的参数数量动态调整大小。

如果我知道参数的数量,我可以像这样使用选择函数:

=CHOOSE(SEQUENCE(number_of_args), arg_1, arg_2, arg_3, ...))

但我不想将参数数量作为参数传递,我希望它是动态的。一个想法是使用

ISOMITTED(arg_n)
进行二分搜索以找到第一个缺失的参数。但这仍然硬编码了我的 ARRAY 函数的参数数量上限,更不用说创建一个讨厌的硬编码二叉树了。


使用 VBA 当然很容易:

Public Function ARRAYFROMARGS(ParamArray args()) As Variant
    ARRAYFROMARGS = args
End Function

demo of calling ARRAYFROMARGS

尽管这只能接受可以强制转换为变体的值,因此不能接受 lambda 或链接数据类型。这使得非 VBA 版本更加灵活。

excel vba lambda excel-formula dynamic-arrays
5个回答
2
投票

这并不完全是您正在寻找的,但也许它会提供一些想法?如果我们可以一次取一个值而不是一个列表,那么我们可以使用转义字符 (\) 来让公式知道它不再需要任何值,而不是对参数进行限制,并使公式递归,并利用 MAKEARRAY 通过每个新条目扩展先前创建的数组。请注意,对于引用,第一个引用不得导致错误,因此必须为非空白。

ARRAY
=LAMBDA(val_1,
    LAMBDA(val_2,
        IF(
            TYPE(val_2)=16,val_1,
            ARRAY(
                MAKEARRAY(ROWS(val_1)+1,COLUMNS(val_1),
                    LAMBDA(i,j,
                        IFERROR(INDEX(val_1,i,j),val_2)
                    )
                )
            )
        )
    )
)

ARRAY Examples


2
投票

正如我在问题中提到的,我找到了一种使用二分搜索来评估缺少多少参数的方法。但它确实涉及大量复制粘贴。因此,这里是通过查找丢失的第一个参数来评估传递的参数数量的代码:

标签 价值
姓名 参数计数
范围 作业簿
评论 使用硬编码的二分搜索来查找第一个省略的参数,块最多为 63
参考
=LAMBDA([p_1],[p_2],[p_3],[p_4],[p_5],[p_6],[p_7],[p_8],[p_9],[p_10],[p_11],[p_12],[p_13],[p_14],[p_15],[p_16],[p_17],[p_18],[p_19],[p_20],[p_21],[p_22],[p_23],[p_24],[p_25],[p_26],[p_27],[p_28],[p_29],[p_30],[p_31],[p_32],[p_33],[p_34],[p_35],[p_36],[p_37],[p_38],[p_39],[p_40],[p_41],[p_42],[p_43],[p_44],[p_45],[p_46],[p_47],[p_48],[p_49],[p_50],[p_51],[p_52],[p_53],[p_54],[p_55],[p_56],[p_57],[p_58],[p_59],[p_60],[p_61],[p_62],[p_63],IF(ISOMITTED(p_32),IF(ISOMITTED(p_16),IF(ISOMITTED(p_8),IF(ISOMITTED(p_4),IF(ISOMITTED(p_2),IF(ISOMITTED(p_1),0,1),IF(ISOMITTED(p_3),2,3)),IF(ISOMITTED(p_6),IF(ISOMITTED(p_5),4,5),IF(ISOMITTED(p_7),6,7))),IF(ISOMITTED(p_12),IF(ISOMITTED(p_10),IF(ISOMITTED(p_9),8,9),IF(ISOMITTED(p_11),10,11)),IF(ISOMITTED(p_14),IF(ISOMITTED(p_13),12,13),IF(ISOMITTED(p_15),14,15)))),IF(ISOMITTED(p_24),IF(ISOMITTED(p_20),IF(ISOMITTED(p_18),IF(ISOMITTED(p_17),16,17),IF(ISOMITTED(p_19),18,19)),IF(ISOMITTED(p_22),IF(ISOMITTED(p_21),20,21),IF(ISOMITTED(p_23),22,23))),IF(ISOMITTED(p_28),IF(ISOMITTED(p_26),IF(ISOMITTED(p_25),24,25),IF(ISOMITTED(p_27),26,27)),IF(ISOMITTED(p_30),IF(ISOMITTED(p_29),28,29),IF(ISOMITTED(p_31),30,31))))),IF(ISOMITTED(p_48),IF(ISOMITTED(p_40),IF(ISOMITTED(p_36),IF(ISOMITTED(p_34),IF(ISOMITTED(p_33),32,33),IF(ISOMITTED(p_35),34,35)),IF(ISOMITTED(p_38),IF(ISOMITTED(p_37),36,37),IF(ISOMITTED(p_39),38,39))),IF(ISOMITTED(p_44),IF(ISOMITTED(p_42),IF(ISOMITTED(p_41),40,41),IF(ISOMITTED(p_43),42,43)),IF(ISOMITTED(p_46),IF(ISOMITTED(p_45),44,45),IF(ISOMITTED(p_47),46,47)))),IF(ISOMITTED(p_56),IF(ISOMITTED(p_52),IF(ISOMITTED(p_50),IF(ISOMITTED(p_49),48,49),IF(ISOMITTED(p_51),50,51)),IF(ISOMITTED(p_54),IF(ISOMITTED(p_53),52,53),IF(ISOMITTED(p_55),54,55))),IF(ISOMITTED(p_60),IF(ISOMITTED(p_58),IF(ISOMITTED(p_57),56,57),IF(ISOMITTED(p_59),58,59)),IF(ISOMITTED(p_62),IF(ISOMITTED(p_61),60,61),IF(ISOMITTED(p_63),62,63)))))))

更容易复制版本这里

它是这样被称为

=ARGSCOUNT(arg_1, arg_2, ..., arg_63)
的,来自封闭的 LAMBDA。请注意,它最多需要 63 个可选参数,因为我的二叉树是对称的,因此必须是 2 的幂(0 个参数的情况下为负 1),并且命名引用的字符限制较低,约为 2000 个。但是,您可以多次调用它来自父函数并对结果求和,例如
ARGSCOUNT(arg_1, ..., arg_63) + ARGSCOUNT(arg_64, ..., arg_126)

然后可以在第二个 LAMBDA 函数中使用该计数来构建数组:

标签 价值
姓名 阵列
范围 作业簿
评论 从逗号分隔的参数创建一个数组,最多 130 个
参考
=LAMBDA(_0,[_1],[_2],[_3],[_4],[_5],[_6],[_7],[_8],[_9],[_10],[_11],[_12],[_13],[_14],[_15],[_16],[_17],[_18],[_19],[_20],[_21],[_22],[_23],[_24],[_25],[_26],[_27],[_28],[_29],[_30],[_31],[_32],[_33],[_34],[_35],[_36],[_37],[_38],[_39],[_40],[_41],[_42],[_43],[_44],[_45],[_46],[_47],[_48],[_49],[_50],[_51],[_52],[_53],[_54],[_55],[_56],[_57],[_58],[_59],[_60],[_61],[_62],[_63],[_64],[_65],[_66],[_67],[_68],[_69],[_70],[_71],[_72],[_73],[_74],[_75],[_76],[_77],[_78],[_79],[_80],[_81],[_82],[_83],[_84],[_85],[_86],[_87],[_88],[_89],[_90],[_91],[_92],[_93],[_94],[_95],[_96],[_97],[_98],[_99],[_100],[_101],[_102],[_103],[_104],[_105],[_106],[_107],[_108],[_109],[_110],[_111],[_112],[_113],[_114],[_115],[_116],[_117],[_118],[_119],[_120],[_121],[_122],[_123],[_124],[_125],[_126],[_127],[_128],[_129],CHOOSE(SEQUENCE(ARGSCOUNT(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,_61,_62,_63)+ARGSCOUNT(_64,_65,_66,_67,_68,_69,_70,_71,_72,_73,_74,_75,_76,_77,_78,_79,_80,_81,_82,_83,_84,_85,_86,_87,_88,_89,_90,_91,_92,_93,_94,_95,_96,_97,_98,_99,_100,_101,_102,_103,_104,_105,_106,_107,_108,_109,_110,_111,_112,_113,_114,_115,_116,_117,_118,_119,_120,_121,_122,_123,_124,_125,_126)+ARGSCOUNT(_127,_128,_129)+1),_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,_61,_62,_63,_64,_65,_66,_67,_68,_69,_70,_71,_72,_73,_74,_75,_76,_77,_78,_79,_80,_81,_82,_83,_84,_85,_86,_87,_88,_89,_90,_91,_92,_93,_94,_95,_96,_97,_98,_99,_100,_101,_102,_103,_104,_105,_106,_107,_108,_109,_110,_111,_112,_113,_114,_115,_116,_117,_118,_119,_120,_121,_122,_123,_124,_125,_126,_127,_128,_129))

我知道这很讨厌,但这让你可以访问一个令人惊讶的简单功能:

=ARRAY(A1, A2, 3, "foo", "bar") // array of anything, dynamically sized

ARRAY function


奖励:

您甚至可以创建一个 LAMBDAS 数组来传递给诸如地图之类的东西:

=MAP(ARRAY(LAMBDA(x, x^2), LAMBDA(y, y+1)),LAMBDA(f, f(3)) // -> {9,4} i.e. 3^2, 3+1

...并且 vba ARRAYFROMARGS 函数不能将 LAMBDAS 作为参数。


1
投票

VSTACK
现已存在,它履行了这一职责。

例如,

enter image description here


0
投票

为了完整性,现在可以使用

HSTACK
VSTACK
来实现,它们在帖子发布时尚未发布。但是,要定义您自己的可变参数函数,您需要遵循上述方法之一。

例如

=printf("{1} {2}!","Hello","World")
采用任意数量的后续参数定义如下https://codereview.stackexchange.com/questions/268446/printf1-2-in-excel-without-vba-lambda-functions-with-variable

=LAMBDA(
    mask,
    _0,[_1],[_2],[_3],[_4],[_5],[_6],[_7],[_8],[_9],[_10],[_11],[_12],[_13],[_14],[_15],[_16],[_17],[_18],[_19],[_20],[_21],[_22],[_23],[_24],[_25],[_26],[_27],[_28],[_29],[_30],[_31],[_32],[_33],[_34],[_35],[_36],[_37],[_38],[_39],[_40],[_41],[_42],[_43],[_44],[_45],[_46],[_47],[_48],[_49],[_50],[_51],[_52],[_53],[_54],[_55],[_56],[_57],[_58],[_59],[_60],[_61],[_62],[_63],[_64],[_65],[_66],[_67],[_68],[_69],[_70],[_71],[_72],[_73],[_74],[_75],[_76],[_77],[_78],[_79],[_80],[_81],[_82],[_83],[_84],[_85],[_86],[_87],[_88],[_89],[_90],[_91],[_92],[_93],[_94],[_95],[_96],[_97],[_98],[_99],[_100],[_101],[_102],[_103],[_104],[_105],[_106],[_107],[_108],[_109],[_110],[_111],[_112],[_113],[_114],[_115],[_116],[_117],[_118],
    LET(
        tokensArray,
        FLATARRAY(
            _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, _118
        ),
        escapedResult,
        _ReplaceRecursive(
            mask,
            tokensArray,
            1,
            ROWS(tokensArray)
        ),
        SUBSTITUTE(escapedResult,"\}","}")
    )
)

-1
投票

如果

Array1
定义为:

=CHOOSE(SEQUENCE(number_of_args), arg_1, arg_2, arg_3, ..., arg_n))

其中

number_of_args
使得
number_of_args >= n
,那么您想要的结果是通过以下方式得出的:

=INDEX(Array1,SEQUENCE(SUM(1-ISERR(Arry1))))
© www.soinside.com 2019 - 2024. All rights reserved.