Mathematica:获取传递给函数的参数数量?

发布于 2024-09-05 09:09:26 字数 149 浏览 4 评论 0原文

如何获取传递给函数的参数数量,例如 Plus[2,3,4,5] 有 4 个参数传递给它。我想这可能涉及使用函数 Length 并将参数放入列表中。目的是根据函数的参数数量迭代操作。可能有一个简单的解决方案或功能,但我还没有遇到过。还有其他方法或建议也欢迎吗?

How do I get the number of arguments passed to a function, such as Plus[2,3,4,5] has 4 arguments passed to it. I was thinking it may involve the use of the function Length and getting the arguments into a list. The intention is to iterate an operation based on the number of arguments for a function. There is probably a simple solution or function but I haven't come across it yet. Any other ways or suggestions are welcome as well?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

豆芽 2024-09-12 09:09:26

一种方法是:

In[1]:= foo[args___] := Length[{args}]

In[2]:= foo[1,2,3,4]
Out[2]= 4

当您定义这样的函数时,模式 args___ (带有 3 个尾随下划线)将匹配 0 个或多个事物的序列。您不能在 Sequence 上使用 Length 并发生任何明智的事情,因此您应该将 args 包装在 List 中> ({})首先。

然而,贝利萨留是正确的。对于大量迭代操作,使用内置的高阶函数(例如 MapFold)会更容易、更高效。

编辑添加:由于 Mathematica 表达式是在边界检查数组之上构建的,长度 的时间是 O (1)。这可能会让您相信 foo also 具有 O (1) 复杂性,但您错了。由于模式匹配的工作方式,args 匹配的所有元素都将复制到新的 List 中,然后将其传递给 < code>Length,复杂度为 O (N)。这不一定是一个大问题,因为在函数中使用非常大的参数列表几乎总是意味着使用 Apply,这会执行 O (N >) 无论如何都要复制,但这是你应该知道的事情。

再次编辑添加:还有另一种方法可以直接在正在计算的表达式上使用Length来执行此操作(与大多数 Mathematica 面向列表的函数一样,Length > 可用于具有任何头的表达式,而不仅仅是列表)。没有复制任何内容,因为没有序列匹配并给出新头,并且对其参数进行计数的函数不需要具有任何特殊属性,例如 HoldAll。尽管如此,这是一个卑鄙的黑客,通过引入实际上不属于副作用的副作用来利用模式匹配机制中的一个怪癖,所以我会非常谨慎地使用它,如果有的话:

Module[{n},
 expr : foo[___] /; (n = Length[Unevaluated[expr]]; True) :=
  n]

变量 n 可以是全局的,但是 Module 将创建(或至少很好地伪造)词法闭包,因此您至少可以将变量保留在本地。

Here's one way:

In[1]:= foo[args___] := Length[{args}]

In[2]:= foo[1,2,3,4]
Out[2]= 4

When you define a function like this, the pattern args___ (with 3 trailing underscores) will match a Sequence of 0 or more things. You can't use Length on a Sequence and have anything sensible happen, so you should wrap args in a List (the {}) first.

However, belisarius is correct. For a lot of iterative operations, it will be easier and more efficient to use built-in higher-order functions like Map and Fold.

EDIT to add: Due to way that Mathematica expressions are built on top of bounds-checked arrays, Length is O (1) in time. This might lead you to believe that foo also has O (1) complexity, but you would be wrong. Due to the way pattern-matching works, all of the elements matched by args will be copied into the new List that you then pass to Length, making the complexity O (N). This isn't necessarily a huge problem, because using really huge argument lists with a function almost invariably means using Apply, which does an O (N) copy anyway, but it's something you should know.

EDIT again to add: There's another way to do this using Length directly on the expression being evaluated (like most of Mathematica's list-oriented functions, Length can be used on expressions with any head, not just lists). Nothing is copied because no sequences are matched and given new heads, and the function which is having its arguments counted need not have any special attributes like HoldAll. Nonetheless, it is a sleazy hack that exploits a quirk in the pattern-matching machinery by introducing side-effects where side-effects really don't belong, so I would use it with extreme caution, if at all:

Module[{n},
 expr : foo[___] /; (n = Length[Unevaluated[expr]]; True) :=
  n]

The variable n could be global, but Module will create (or at least do a good job faking) lexical closures, so you can at least keep your variables local.

苏辞 2024-09-12 09:09:26

我认为你将不得不开始干扰Mathematica的评估序列,或者可能更简单,干扰其内在函数的属性。您遇到的问题之一是 Mathematica 计算非常贪婪,因此当您输入 Plus[2,3,4,5] 后按回车键时,它已经完成了它的内容并返回 14。

您可能会摆弄 $Pre 来实现您想要的。但您可能必须Unprotect[Plus] 并强制它Hold 其参数,直到您有机会计算出有多少个参数。

当然,如果您只是使用 Plus 作为示例,并且确实想定义自己的函数,那么您的任务可能会容易得多。这是我编写的一个函数,它仅返回它获得的参数数量:

fun[y___]:=Length[{y}]

我已经在一些简单的情况下对此进行了测试。尝试以下操作对您会很有启发:

fun[1,{2,3}]

我倾向于同意已经发表的评论,您建议做的事情并不是很Mathematica-al

I think that you are going to have to start intefering with Mathematica's evaluation sequence or, possibly simpler, interfering with the properties of its intrinsic functions. One of the problems you have is that Mathematica evaluates very greedily, so by the time you have pressed return after entering Plus[2,3,4,5] it has done its stuff and returned 14.

You could possibly fiddle with $Pre to achieve what you want. But you might have to Unprotect[Plus] and force it to Hold its arguments until you've had a chance to count how many there are.

Of course, if you were just using Plus as an example and really want to define a function of your own then your task is probably a lot easier. Here is a function I wrote which simply returns the number of arguments it gets:

fun[y___]:=Length[{y}]

I've tested this on some simple cases. It will be instructive for you to try things like:

fun[1,{2,3}]

I tend to agree with the comment already made, that what you propose to do is not very Mathematica-al

喜你已久 2024-09-12 09:09:26

根据我在另一个答案中的评论,执行此操作的惯用方法通常是:

Length[Unevaluated[expr]]

例如:

In[1]:= Length[Unevaluated[Plus[1, 2, 3, 4]]]

Out[1]= 4

使用 Unevaluated 可以防止参数评估,避免参数为 Length 的情况(没有任何 Hold* 属性)将计算为没有长度的原子值(如数字),并且 Length 返回 0在这种情况下:

In[2]:= Length[Plus[1, 2, 3, 4]]

Out[2]= 0

Per my comments in another answer, the idiomatic way to do this is typically:

Length[Unevaluated[expr]]

E.g.:

In[1]:= Length[Unevaluated[Plus[1, 2, 3, 4]]]

Out[1]= 4

The use of Unevaluated prevents the argument from evaluating, avoiding the situation where the argument to Length (which does not have any Hold* attributes) would evaluate to an atomic value (like a number) which doesn't have a length, and Length returns 0 in such cases:

In[2]:= Length[Plus[1, 2, 3, 4]]

Out[2]= 0
冷月断魂刀 2024-09-12 09:09:26

您始终可以使用列表:

f[list_]:= (len = Length[list];
            While [....
                   do whatever
                 ];
            Return [ ..];
           );

 myOut= f[{a,b,c}];

这种方式适合与 Mathematica 一起使用,因为列表管理功能非常强大。

如果您使用 f[a,b,c],参数的数量是硬编码的

但是再次......尝试函数式方式。

You can always use lists:

f[list_]:= (len = Length[list];
            While [....
                   do whatever
                 ];
            Return [ ..];
           );

 myOut= f[{a,b,c}];

This way is appropriate to use with Mathematica because list management is very powerful.

If you use f[a,b,c], the number of arguments is hard-coded

But again ... try the functional way.

想念有你 2024-09-12 09:09:26

不确定您需要哪种递归,但根据我的经验(受 Haskel 启发?)函数定义中的 first,rest 模式可能非常强大:

f[onearg_]:=onearg
f[first_,rest__]:=first+2 f[rest]

In[148]= Trace@f[2,3,4]
Out[148]= {f[2,3,4],2+2 f[3,4],{{f[3,4],3+2 f[4],{{f[4],4},2 4,8},3+8,11},2 11,22},2+22,24}

当然,您可以访问 长度[{rest}](如果需要)。

编辑2:(正如 Pilsy 指出的那样,旧图是不正确的)Mathematica 实际上复制了“其余”部分,因此如果实际函数的成本可以忽略不计,则缩放比例会变成二次方。

f[] := 0;
f[onearg_] := onearg[[1, 1]];
f[first_, rest__] := f[first] + f[rest];
ListLogLogPlot[Part[#, -1, 1],
   Joined -> True, PlotRange -> {{100, All}, Automatic}, 
   AxesLabel -> {"#Arguments", "Runtime"}] &@
 Reap@Nest[
   Function[all, 
    Sow[{Length[all], First@Timing[Table[f @@ all, {10}]]}];
    Join[all, RandomReal[{-1, 1}, {10, 10, 10}]]], {}, 100]

下图显示了上面的廉价内部函数 f[onearg_]:=onearg[[1,1]] 的输出,其中缩放比例确实是参数数量的二次方,而对于昂贵的内部函数函数 f[onearg_]:=SingularValueList[onearg,1],其中缩放更接近线性。

上述代码的输出

Not sure what kind of recursion you need, but in my experience a (Haskel inspired?) first,rest pattern in your function definition can be quite powerful:

f[onearg_]:=onearg
f[first_,rest__]:=first+2 f[rest]

In[148]= Trace@f[2,3,4]
Out[148]= {f[2,3,4],2+2 f[3,4],{{f[3,4],3+2 f[4],{{f[4],4},2 4,8},3+8,11},2 11,22},2+22,24}

And of course, you have access to Length[{rest}] if you need it.

EDIT 2: (Old plot was incorrect as pointed out by Pilsy) Mathematica actually copies the 'rest' part, so that the scaling turns quadratic if the cost of the actual function is negligible.

f[] := 0;
f[onearg_] := onearg[[1, 1]];
f[first_, rest__] := f[first] + f[rest];
ListLogLogPlot[Part[#, -1, 1],
   Joined -> True, PlotRange -> {{100, All}, Automatic}, 
   AxesLabel -> {"#Arguments", "Runtime"}] &@
 Reap@Nest[
   Function[all, 
    Sow[{Length[all], First@Timing[Table[f @@ all, {10}]]}];
    Join[all, RandomReal[{-1, 1}, {10, 10, 10}]]], {}, 100]

The figure below shows the output for an inexpensive inner function f[onearg_]:=onearg[[1,1]] as above where the scaling is indeed quadratic in number of arguments, and for an expensive inner function f[onearg_]:=SingularValueList[onearg,1], where the scaling is closer to linear.

output of above code

给我一枪 2024-09-12 09:09:26

上面的一些解决方案要求您将参数显式输入到一个函数中,该函数将其放入列表中。通过我自己的研究,我发现有一种方法可以计算答案。给定表达式 3 + 2*2*2*4 + 5,找出传递给 Times 函数的参数数量。在使用 TreeForm 函数将其可视化的帮助下,我将一些 mathematica 的内置函数放在一起来评估答案。

步骤:
1/ 获取函数的位置。
2/ 它返回一个嵌套列表。
3/ 扁平化列表。
4/ 获取列表的长度,该长度将是函数参数所在的级别。
5/ Level 返回一个参数列表,然后您可以获取其长度。

示例:

In[89]:= Position[Hold[3 + 2*2*2*4 + 5], Times]

Out[89]= (1    2    0)

In[90]:= FullForm[%]

Out[90]= List[List[1,2,0]]

In[91]:= Flatten[%]

Out[91]= {1,2,0}

In[92]:= FullForm[%]

Out[92]= List[1,2,0]

In[93]:= Length[%]

Out[93]= 3

In[94]:= Level[Hold[3 + 2*2*2*4 + 5], {%}]

Out[94]= {2,2,2,4}

In[95]:= Length[%]

Out[95]= 4

这一切都可以放入一个函数中。
尽管它可能无法以自动方式处理表达式中存在同一函数的两个实例的情况。这可能需要用户设置或输入一些条件。

Some of the solutions above require that you input the arguments explicitly into a function which puts it in a list. With my own study I have found there is way to calculate the answer. Given the expression 3 + 2*2*2*4 + 5, find how many arguments are passed to the Times function. With a bit of help visualising it with the TreeForm function, I put together some of mathematica's built in functions to evaluate an answer.

Steps:
1/ Get position of the function.
2/ It returns a nested list.
3/ Flatten list.
4/ Get list's length which will be the level that the arguments of the function are at.
5/ Level returns a list of the arguments which you can then get the length of.

Example:

In[89]:= Position[Hold[3 + 2*2*2*4 + 5], Times]

Out[89]= (1    2    0)

In[90]:= FullForm[%]

Out[90]= List[List[1,2,0]]

In[91]:= Flatten[%]

Out[91]= {1,2,0}

In[92]:= FullForm[%]

Out[92]= List[1,2,0]

In[93]:= Length[%]

Out[93]= 3

In[94]:= Level[Hold[3 + 2*2*2*4 + 5], {%}]

Out[94]= {2,2,2,4}

In[95]:= Length[%]

Out[95]= 4

This could all be put in a function.
Though it may not handle the case when there are two instances of the same function within an expression in an automated way. This may require some condition set or input by the user.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文