Patterns

Simple Patterns

Patterns and how to use them might be the most important thing to understand in Mathematica

At some level, due to its expression-centered structure, Mathematica is just a huge pattern matching machine

The most basic pattern is just an underscore, but of course it has an expression structure:

_ // FullForm

(*Out:*)

Blank[]

We can also provide a name for our pattern which has in various function

p_//FullForm

(*Out:*)

Pattern[p,Blank[]]

You’ll notice the Blank[] remains. Blank[] matches any single expression. For pattern matching there’s the function MatchQ . It will return whether the expression as in its first argument matches the pattern in its second.

It doesn’t have to have a pattern as its second argument though:

MatchQ[a,a]

(*Out:*)

True

But the following will also match:

MatchQ[a,_]

(*Out:*)

True

MatchQ[a,p_]

(*Out:*)

True

Patterns can also have a Head that must match, which is specified after the underscore.

_a//FullForm

(*Out:*)

Blank[a]

With a head all the following match:

MatchQ[a[],_a]

(*Out:*)

True

MatchQ[a[1,2,3],_a]

(*Out:*)

True

MatchQ[a[a[a[a[a[a[]]]]]],_a]

(*Out:*)

True

But the following won’t:

MatchQ[a,_a]

(*Out:*)

False

Along with a head one can also specify a test condition which will be applied to the thing that’s being matched against

_a?test//FullForm

(*Out:*)

PatternTest[Blank[a],test]

Which means the following will match:

MatchQ[a[1,2,3],_a?(Length@#>1&)]

(*Out:*)

True

But the other cases will not:

MatchQ[a[],_a?(Length@#>1&)]

(*Out:*)

False

MatchQ[a[a[a[a[a[a[]]]]]],_a?(Length@#>1&)]

(*Out:*)

False

Patterns can also be specified as parts of an expression:

MatchQ[a[1,2,3],a[_,_,_]]

(*Out:*)

True

Patterns can also be specified as matching 1 or more elements with a double underscore:

__//FullForm

(*Out:*)

BlankSequence[]

MatchQ[a[1,2,3],a[__]]

(*Out:*)

True

MatchQ[a[],a[__]]

(*Out:*)

False

or 0 or more elements via a triple underscore:

___//FullForm

(*Out:*)

BlankNullSequence[]

MatchQ[a[1,2,3],a[___Integer]]

(*Out:*)

True

MatchQ[a[],a[___]]

(*Out:*)

True

Everything that applies to single element patterns applies as well to these multi-element patterns.

Complex Patterns

Often it’s useful to be able to match more than one type. For this, there’s a built-in head Alternatives , which is represented by a vertical bar |

MatchQ[10,_Integer|_String]

(*Out:*)

True

MatchQ["10",_Integer|_String]

(*Out:*)

True

MatchQ[π,_Integer|_String]

(*Out:*)

False

Alternatives can be used with any pattern and simplifies life tremendously in describing complicated structures concisely

One issue, however, is that a set of alternatives can’t be matched multiple times with the double or triple underscores. To fix this issue there is Repeated ( .. ) and RepeatedNull ( ... ) which have the same meanings as __ and ___ respectively.

Here’s an example of matching complex structure:

MatchQ[RandomChoice[{A,B,C}]@(Sequence@@(
 If[RandomInteger[]==0,ToString@#,#]&/@RandomInteger[10,RandomInteger[10]]
 )),
 (A|B|C)[(_String|_Integer)...]
]

(*Out:*)

True

It is impossible to know ahead of time what the head will be or how many arguments there will be or whether they’ll be strings or integers, but that doesn’t matter. We can still represent this pattern in under one line. Yet the pattern is robust enough that by doing something like appending in a symbol, our pattern catches that:

MatchQ[Append[RandomChoice[{A,B,C}]@(Sequence@@(
 If[RandomInteger[]==0,ToString@#,#]&/@RandomInteger[10,RandomInteger[10]]
 )),RandomChoice[{A,B,C}]],
 (A|B|C)[(_String|_Integer)...]
]

(*Out:*)

False

There is one further useful addition to this current redux on patterns. Sometime you know you’ll, say, see pairs of a patterns, and so a simple .. or __ isn’t precise enough. For this case there is the head PatternSequence which can capture this:

MatchQ[A@@(If[OddQ@#,ToString@#,#]&/@Range[10]),
 A[PatternSequence[_String,_Integer]..]
 ]

(*Out:*)

True

Except

The final piece of patterns is the head Except . It specifies that anything Except the pattern inside should match. It is a negation pattern, in essence.

MatchQ[1,Except[_String]]

(*Out:*)

True

MatchQ[<|a->b|>,Except[_String]]

(*Out:*)

True

MatchQ[Graphics@Disk[],Except[_String]]

(*Out:*)

True

MatchQ["asdasd",Except[_String]]

(*Out:*)

False

results matching ""

    No results matching ""