Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the recommended way to check that a list is a list of numbers in argument of a function?

I've been looking at the ways to check arguments of functions. I noticed that MatrixQ takes 2 arguments, the second is a test to apply to each element.

But ListQ only takes one argument. (also for some reason, ?ListQ does not have a help page, like ?MatrixQ does).

So, for example, to check that an argument to a function is a matrix of numbers, I write

ClearAll[foo]
foo[a_?(MatrixQ[#, NumberQ] &)] := Module[{}, a + 1]

What would be a good way to do the same for a List? This below only checks that the input is a List

ClearAll[foo]
foo[a_?(ListQ[#] &)] := Module[{}, a + 1]

I could do something like this:

ClearAll[foo]
foo[a_?(ListQ[#] && (And @@ Map[NumberQ[#] &, # ]) &)] := Module[{}, a + 1]

so that foo[{1, 2, 3}] will work, but foo[{1, 2, x}] will not (assuming x is a symbol). But it seems to me to be someone complicated way to do this.

Question: Do you know a better way to check that an argument is a list and also check the list content to be Numbers (or of any other Head known to Mathematica?)

And a related question: Any major run-time performance issues with adding such checks to each argument? If so, do you recommend these checks be removed after testing and development is completed so that final program runs faster? (for example, have a version of the code with all the checks in, for the development/testing, and a version without for production).

like image 508
Nasser Avatar asked Jan 09 '12 09:01

Nasser


People also ask

How do you find the number of arguments in a function?

Syntax *args allow us to pass a variable number of arguments to a function. We will use len() function or method in *args in order to count the number of arguments of the function in python.

How do you find the argument of a function in Python?

You can use inspect. getargspec() to see what arguments are accepted, and any default values for keyword arguments. inspect. getargspec() should be considered deprecated in Python 3.

What is the list function in Python?

The list() function creates a list object. A list object is a collection which is ordered and changeable. Read more about list in the chapter: Python Lists.

Can we pass list as argument in Python?

You can send any data types of argument to a function (string, number, list, dictionary etc.), and it will be treated as the same data type inside the function.


1 Answers

You might use VectorQ in a way completely analogous to MatrixQ. For example,

f[vector_ /; VectorQ[vector, NumericQ]] := ...

Also note two differences between VectorQ and ListQ:

  1. A plain VectorQ (with no second argument) only gives true if no elements of the list are lists themselves (i.e. only for 1D structures)

  2. VectorQ will handle SparseArrays while ListQ will not


I am not sure about the performance impact of using these in practice, I am very curious about that myself.

Here's a naive benchmark. I am comparing two functions: one that only checks the arguments, but does nothing, and one that adds two vectors (this is a very fast built-in operation, i.e. anything faster than this could be considered negligible). I am using NumericQ which is a more complex (therefore potentially slower) check than NumberQ.

In[2]:= add[a_ /; VectorQ[a, NumericQ], b_ /; VectorQ[b, NumericQ]] :=
  a + b

In[3]:= nothing[a_ /; VectorQ[a, NumericQ], 
  b_ /; VectorQ[b, NumericQ]] := Null

Packed array. It can be verified that the check is constant time (not shown here).

In[4]:= rr = RandomReal[1, 10000000];

In[5]:= Do[add[rr, rr], {10}]; // Timing

Out[5]= {1.906, Null}

In[6]:= Do[nothing[rr, rr], {10}]; // Timing

Out[6]= {0., Null}

Homogeneous non-packed array. The check is linear time, but very fast.

In[7]:= rr2 = Developer`FromPackedArray@RandomInteger[10000, 1000000];

In[8]:= Do[add[rr2, rr2], {10}]; // Timing

Out[8]= {1.75, Null}

In[9]:= Do[nothing[rr2, rr2], {10}]; // Timing

Out[9]= {0.204, Null}

Non-homogeneous non-packed array. The check takes the same time as in the previous example.

In[10]:= rr3 = Join[rr2, {Pi, 1.0}];

In[11]:= Do[add[rr3, rr3], {10}]; // Timing

Out[11]= {5.625, Null}

In[12]:= Do[nothing[rr3, rr3], {10}]; // Timing

Out[12]= {0.282, Null}

Conclusion based on this very simple example:

  1. VectorQ is highly optimized, at least when using common second arguments. It's much faster than e.g. adding two vectors, which itself is a well optimized operation.
  2. For packed arrays VectorQ is constant time.

@Leonid's answer is very relevant too, please see it.

like image 68
Szabolcs Avatar answered Sep 27 '22 19:09

Szabolcs