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?
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.
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
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With