用于在不使用VBA的情况下根据值构造数组的Excel函数

nkkqxpd9  于 2022-11-18  发布在  其他
关注(0)|答案(4)|浏览(169)
  • 注意:此问题涉及一些功能,如可选的LAMBDA参数和ISOMITTED函数,这些功能仅在Beta通道(更多信息here)中可用(撰写本文时)*

我试图在Excel LAMBDA函数中模拟VBA的paramarray,因此希望使用以下函数:

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

...返回数组{arg_1, arg_2, arg_3, ...},该数组根据传递的参数数量动态调整大小。
如果我知道参数的个数,我就可以像这样使用choose函数:

=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

虽然它只接受可以强制转换为变量的值,而不是lambda或链接的数据类型。这使得非VBA版本更灵活。

gopyfrb3

gopyfrb31#

VSTACK,其现在存在,其满足该角色。
例如:

kd3sttzy

kd3sttzy2#

正如我在问题中提到的,我已经找到了一种使用折半搜索来计算缺少多少参数的方法。不过,这确实涉及到大量的复制粘贴操作。因此,下面的代码通过查找第一个缺少的参数来计算传递的参数的数量:
| 标签|数值|
| - -|- -|
| 名称名称名称|参数计数|
| 适用范围|工作簿|
| 备注|使用硬编码的二分搜索查找第一个省略的参数,最多为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)))))))|

  • 更易于复制here版本 *

它是这样调用的=ARGSCOUNT(arg_1, arg_2, ..., arg_63)从封闭的LAMBDA。注意,它需要多达63个可选的参数,因为我的二叉树是对称的,所以必须是2的幂(如果没有参数,则为-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

奖励:

您甚至可以创建一个LAMBDAS数组来传递给map之类的对象:

=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作为参数。

vktxenjb

vktxenjb3#

这并不是你想要的,但是也许它会给予你一些想法?如果我们可以一次取一个值,而不是一个列表,那么我们可以有一个转义字符,而不是对参数有一个限制(\)让公式知道它不应该再期望值,并使公式递归,并利用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)
                    )
                )
            )
        )
    )
)

nlejzf6q

nlejzf6q4#

如果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))))

相关问题