What’s in, docs?

2012-10-08 by verbeia. 4 comments

After using Mathematica for a while, you start to think you are on top of the richness of the language. You become familiar with a range of different functions and programming styles. But in fact, you haven’t even scratched the surface.

I can’t emphasize enough how important it is to look up the documentation from time to time, even for the functions you think you already know. There are so many options and additional arguments to workhorse functions that you might not have appreciated. Here are a few of my favorites. Some of them were noted in a question I once asked about the issue.

Hooray for Array

If you want to iterate over arbitrary objects, you need Table.

Table[f[i], {i, {a, b, whatever}}]
{f[a], f[b], f[whatever]}

If instead the iterator increments by one each time, Array is cleaner. You don’t even need to give the iterator a name.

Array[f, 3]
{f[1], f[2], f[3]}

It’s easy to forget the extended forms of standard functions like this. The iterator in Array does not have to start at 1. Don’t forget that the first argument gives the resulting list’s length, not the end value of the iterator.

Array[f, {3}, {5}]
{f[5], f[6], f[7]}

This is a general example of the flexible pattern-matching in Mathematica, which allows separate function definitions for different numbers and types of arguments.

Totally rad

Total[somematrix, {2}] 

is equivalent to Mapping the Total function onto the rows of the matrix.

Partition magic

The third argument to Partition defines the offset, so that instead of

Partition[Array[f, 5], 2] // TableForm
f[1]    f[2]
f[3]    f[4]

You get

Partition[Array[f, 5], 2, 1] // TableForm
f[1]    f[2]
f[2]    f[3]
f[3]    f[4]
f[4]    f[5]

This means that, for example

Divide @@@ Partition[somevector, 2, 1] 

is equivalent to


This question on the Mathematica.SE site shows how to generalise Partition for ragged lists (i.e., those with sub-lists that are not all the same length). There are a number of different ways to do this, including using Partition itself, as well as various combinations of NestWhile and Prepend.

Join in the fun

The third argument of Join is also incredibly useful. How many times have you seen complicated code with Transpose and Append all over the place, just to join two matrices by column, instead of by row? The default syntax for Join joins the rows, but you can join by columns with just two extra keystrokes. As noted in the answers to this question, this is also usually a little faster than the little-known but highly useful ArrayFlatten function.

Join[Array[g, {4, 2}], Array[f, {4, 2}]] // TableForm
g[1,1]  g[1,2]
g[2,1]  g[2,2]
g[3,1]  g[3,2]
g[4,1]  g[4,2]
f[1,1]  f[1,2]
f[2,1]  f[2,2]
f[3,1]  f[3,2]
f[4,1]  f[4,2]

Join[Array[g, {4, 2}], Array[f, {4, 2}], 2] // TableForm g[1,1] g[1,2] f[1,1] f[1,2] g[2,1] g[2,2] f[2,1] f[2,2] g[3,1] g[3,2] f[3,1] f[3,2] g[4,1] g[4,2] f[4,1] f[4,2]

Flip and Flatten

There are also additional options and arguments in some other basic list-manipulation commands. For example, most experienced users know that Flatten takes a level specification. For example, Flatten[list,1] turns a three-dimensional tensor into a matrix.

Flatten[Array[f, {3, 3, 2}], 1] // TableForm
f[1,1,1]    f[1,1,2]
f[1,2,1]    f[1,2,2]
f[1,3,1]    f[1,3,2]
f[2,1,1]    f[2,1,2]
f[2,2,1]    f[2,2,2]
f[2,3,1]    f[2,3,2]
f[3,1,1]    f[3,1,2]
f[3,2,1]    f[3,2,2]
f[3,3,1]    f[3,3,2]

But did you know that the second argument can also be a matrix? This popular question on the Mathematica.SE site contains a lot of information about how it works. It can be used to Transpose ragged lists, as this answer explains.

Speaking of Transpose, consider what is possible using its second argument. Here is the result of a normal transpose on a three-dimensional list with dimensions 342.

t1 = Transpose[Array[f, {3, 4, 2}]]
{{{f[1, 1, 1], f[1, 1, 2]}, {f[2, 1, 1], f[2, 1, 2]}, {f[3, 1, 1], f[3, 1, 2]}}, {{f[1, 2, 1], f[1, 2, 2]}, {f[2, 2, 1], f[2, 2, 2]}, {f[3, 2, 1], f[3, 2, 2]}}, {{f[1, 3, 1], f[1, 3, 2]}, {f[2, 3, 1], f[2, 3, 2]}, {f[3, 3, 1], f[3, 3, 2]}}, {{f[1, 4, 1], f[1, 4, 2]}, {f[2, 4, 1], f[2, 4, 2]}, {f[3, 4, 1], f[3, 4, 2]}}}

Effectively it treats the list as a matrix to transpose normally: it just happens that the elements of that matrix are themselves lists.

{4, 3, 2}

You can get a completely different result by choosing a different specification in the second argument of Transpose. (The default is equivalent to specifying {2,1,3} for the second argument.)

t2 = Transpose[Array[f, {3, 4, 2}], {2, 3, 1}]
{{{f[1, 1, 1], f[1, 2, 1], f[1, 3, 1], f[1, 4, 1]}, {f[2, 1, 1], 
   f[2, 2, 1], f[2, 3, 1], f[2, 4, 1]}, {f[3, 1, 1], f[3, 2, 1], 
   f[3, 3, 1], f[3, 4, 1]}}, {{f[1, 1, 2], f[1, 2, 2], f[1, 3, 2], 
   f[1, 4, 2]}, {f[2, 1, 2], f[2, 2, 2], f[2, 3, 2], 
   f[2, 4, 2]}, {f[3, 1, 2], f[3, 2, 2], f[3, 3, 2], f[3, 4, 2]}}}

{2, 3, 4}

The Bottom Line

Bottom line? Even if you are an experienced Mathematica user, it is worth having a good look at the documentation for basic functions from time to time. You might be missing some of the power they contain in their optional arguments.