Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matching a Finite Range of Elements with Patterns

While working on my answer to this question, it occurred to me that it is difficult to match a finite range of elements. With the built in patterns, you can match 1 element (_), 1 or more elements (__), or zero or more elements (___). To match more than one element, I used PatternSequence, like this

a:PatternSequence[_,_,_]

or, more generically

a:PatternSequence@@Array[_&,3].

(Using a Condition would have also worked.) To match a range of n to m elements we could do

a:Alternatives@@( PatternSequence @@@ Array[_&, {n,m}] ),

but that is a rather convoluted way to accomplish something that can be done by

a__ /; n <= Length[{a}] <= m.

However, this brings up an interesting question, using the Condition form it is straightforward to match the range 0 to n,

a___ /; Length[{a}] <= n,

but can this be done using patterns alone, i.e. without using Condition (/;)? More specifically, how would one go about matching 0 elements without adding a condition? Also, which is faster?

like image 928
rcollyer Avatar asked Aug 19 '11 13:08

rcollyer


1 Answers

Maybe you could do something with Repeated. E.g.

Cases[{{1, 2, 3}, {1}, {1, 2, 3, 4, 5}, {1,2}}, {Repeated[_, {2, 4}]}]

gives the same result as

Cases[{{1, 2, 3}, {1}, {1, 2, 3, 4, 5}, {1,2}}, {a___ /; 2 <= Length[{a}] <= 4}]

The first method seems faster than the second. For example

tab = Table[Range[RandomInteger[1000]], {1000}];
Timing[t1 = Cases[tab, {a___ /; 0 <= Length[{a}] <= 100}];]
Timing[t2 = Cases[tab, {Repeated[_, {0, 100}]}];]
SameQ[t1, t2]

returns on my system

{0.027801, Null}

{0.000733, Null}

True
like image 108
Heike Avatar answered Nov 03 '22 21:11

Heike