Message Boards Message Boards

1
|
6900 Views
|
22 Replies
|
7 Total Likes
View groups...
Share
Share this post:

What is the pattern for an argument that must be a List of Integers

Given a function f defined as f[x] := .....
I understand that x
can be anything.
If I want the argument x to be an Int, I would write f[xInteger] := ....
If I want the argument x to be a List, I would write f[x
List] := ......
My question is now how would I specify that the argument x MUST BE a list of Ints so that I can call f like this f[{1,2,3}]

POSTED BY: Henrick Jeanty
22 Replies
F[x:{(_Integer)…}] := x ?
POSTED BY: Sander Huisman
Posted 3 years ago

What would be nice would be able to give a pattern a name...

You can certainly do this.

MyPattern = {_String, {__Integer}, _Symbol}

TheSymbols[structs : {MyPattern ...}] := structs[[All, -1]]

TheSymbols[{{"a", RandomInteger[10, 2], abc}, {"b", RandomInteger[10, 2], xyz}}]
(*returns {abc, xyz}*)
POSTED BY: Eric Rimbey

Here's a recursive pattern test that checks for lists of lists of...of lists of integers, that is, of arbitrarily nested lists of integers.

nestedListOfIntegerQ = MatchQ[#, {(_Integer | _?nestedListOfIntegerQ) ...}] &;

f[x_?nestedListOfIntegerQ] := Depth[x];

More examples of nested lists:

MatchQ[{1, 2, 3}, _?nestedListOfIntegerQ]
(*  True  *)

MatchQ[{{1, 2, 3}, {4, 5, 6}}, _?nestedListOfIntegerQ]
(*  True  *)

MatchQ[{{2}, {3, {4}, 5}}, _?nestedListOfIntegerQ]
(*  True  *)

(* Allows empty lists *)
MatchQ[{{}, {{}}}, _?nestedListOfIntegerQ]
(*  True  *)

Use double-dot .. (Repeated) instead of the triple-dot ... (RepeatedNull) to match nested lists, none of which are empty. If you want a mix, you'll have to specify an explicit pattern for the specific mix.

POSTED BY: Michael Rogers

If you name the pattern, then all matches have to be the same expression:

MatchQ[{1.1, 2., 3 + 1}, {(e_ /; e ∈ Reals \[And] e > 1) ...}]
(*  False  : named, all three numbers are different *)

MatchQ[{2., 2., 2.}, {(e_ /; e ∈ Reals \[And] e > 1) ...}]
(*  True   : names, all are the Real 2. *)

MatchQ[{2., 2., 2}, {(e_ /; e ∈ Reals \[And] e > 1) ...}]
(*  False  : named, mix of Real 2. and Integer 2 -- not the same, even if equal *)

MatchQ[{2, 2, 2}, {(e_ /; e ∈ Reals \[And] e > 1) ...}]
(*  True   : named, all are the Integer 2 *)

MatchQ[{1.1, 2., 3 + 1}, {_?(# ∈ Reals \[And] # > 1 &) ...}]
(*  True   : unnamed pattern *)

The last with a PatternTest instead of a Condition is how to create the pattern with RepeatedNull.

POSTED BY: Michael Rogers

Hi Werner,

The ways I can think of immediately are three or four. Since PatternTest takes as an argument only the whole expression to be tested, if you want to test a relationship between its parts, then you have to get at the parts in some way.

Your first way, with Part, seems clear except for the mass of punctuation symbols. The [[]] can be replaced by words, First and Last. Since the length of # is 2, Last[#] gives the same result as #[[2]]. This might be appealing to some people:

MatchQ[{{1, 2}, {Pi, 3.2}}, {{_, _}?(#[[1]] < #[[2]] &) ...}]
(*True  *)

MatchQ[{{1, 2}, {Pi, 3.2}}, {{_, _}?(First[#] < Last[#] &) ...}]
(*True  *)

Here is a Less readable version (hope you don't mind a pun):

MatchQ[{{1, 2}, {Pi, 3.2}}, {{_, _}?(Less @@ # &) ...}]
(*  True  *)

I hope the following is not confusing. The named patterns in {x_, y_} are a separate from the nameless pattern {_, _} being tested and repeated:

MatchQ[{{1, 2}, {Pi, 3.2}}, {{_, _}?(MatchQ[#, {x_, y_} /; x < y] &) ...}]
(*  True  *)

This last way is more verbose and probably a bit less efficient. Maybe it's more readable. If so, then unless you are apply such patterns to large amounts of data, the efficiency is probably not as significant a concern as readability. Frankly, it's took me years and years to get comfortable with patterns. As you learn more, what seems readable changes, too.

Anyway, these are the ideas I could come up with. Pick whichever one you find easiest to deal with.

POSTED BY: Michael Rogers
Posted 2 years ago

It's clear, Hans, that I can always accept any pretty general parameter (parm_ in the most general case) for a function and then test parm through initialization code. But this gives lengthy useless error-checking and -handling coding.

I prefer to define function parameters as sharp as possible and use the nice Wolfram feature that the function is just not called in case of unmatched parameters.

POSTED BY: Werner Geiger
Posted 3 years ago
f[ns : {___Integer}] = whatever  (*this includes an empty list*)
f[ns : {__Integer}] = whatever (*this excludes an empty list*) 
POSTED BY: Eric Rimbey

That works for a list of Integers. Thank you! But how about an argument that could be a List of List of Integers as in calling F[{{1,2,3},{4,5,6}}] ?

POSTED BY: Henrick Jeanty

You would need to do something like:

F[x_?(ArrayQ[#,1|2,IntegerQ])] :=

Look at pattern testing and ArrayQ

POSTED BY: Sander Huisman

I will do that though I have read a lot about patterns. In any case, something that would be great would be a repository of patterns. Some already exist in the documentation, but we would need more. I know that with regular expressions there are dictionaries of patterns for things like: valid credit card #'s phone #'s etc.. What would be nice would be able to give a pattern a name like ListOfIntegers = {_ _ _Integer} then one could compose larger patterns as in ListOfListOfIntegers = {_ _ _ListOfIntegers } meaning a ListOfListOfIntegers is made up of a list of 1 or more ListsOfIntegers

POSTED BY: Henrick Jeanty

Never thought of that! Thank you! So, is there some sort of repository of pattern expressions for commonly used patterns? Things like patterns for URLs, IP addresses, street addresses, etc...?

POSTED BY: Henrick Jeanty

Hello Michael, Thank you very much. I will go and play with what you have taught me.

POSTED BY: Henrick Jeanty
Posted 2 years ago

So, is there some sort of repository of pattern expressions for commonly used patterns? Things like patterns for URLs, IP addresses, street addresses, etc...?

Not patterns but Interpreter can do that.

POSTED BY: Rohit Namjoshi
Posted 2 years ago

I do not understand the Repeated patterns (".." and "..."). Let me explain:

You can pick particular elements matching some conditions out of a list by Cases:

$$\text{Cases}[\{1,2.,3+i\},\text{e$\_$}\text{/;}e\in \mathbb{R}\land e>1]$$

==> {2.}

If you Trace that you can see that Cases applies the conditions on each list element:

$$\text{Trace}[\text{Cases}[\{1,2.,3+i\},\text{e$\_$}\text{/;}e\in \mathbb{R}\land e>1]]$$

==> .....

But I don' t know how to match a list with such properties:

$$\text{MatchQ}[\{1,2.,3+i\},\{(\text{e$\_$}\text{/;}e\in \mathbb{R}\land e>1)\text{...}\}]$$

==> False

... looks nice, but indeed this matches no list at all:

$$\text{MatchQ}[\{1.1,2.,3+1\},\{(\text{e$\_$}\text{/;}e\in \mathbb{R}\land e>1)\text{...}\}]$$

==> False

If you Trace that you can see that MatchQ stops checking after the first list element and returns False in any case:

Hence I cannot define a function that accepts a list of real integers greater than 1.

$$\text{Block}[\{f\},f(\text{xs}:\{(\text{e$\_$}\text{/;}e\in \mathbb{R}\land e>1)\text{...}\})\text{:=}\text{xs}-1;f(\{1.1,2.,3+1\})]$$

==> f[{1.1,2.,4}]

Note that "{(_)...}" is a correct pattern for any list:

$$\text{MatchQ}[\{1.1,2.,3+1\},\{(\_)\text{...}\}]$$

==> True

POSTED BY: Werner Geiger
Posted 2 years ago

Hi Werner,

Hence I cannot define a function that accepts a list of real integers greater than 1.

How about this?

Block[{f},
 f[xs : {a : (_Real | _Integer) ..} /; AllTrue[{a}, # > 1 &]] := xs;
 Print[f[{2., 2, 3 + I}]];
 Print[f[{1., 1}]];
 Print[f[{.5, 2, 3 + 1}]];
 Print[f[{2., 2, 5/2}]];
 Print[f[{2., 1., 3 + 1}]];
 Print[f[{2., 2, 3 + 1}]];
 ]
(*
f[{2.,2,3+I}]
f[{1.,1}]
f[{0.5,2,4}]
f[{2.,2,5/2}]
f[{2.,1.,4}]
{2.,2,4}
*)
POSTED BY: Rohit Namjoshi
Posted 2 years ago

Thanks, Rohit. Of course there many way to achieve my goal. I wanted to understand why I cannot do it with the simple condition:

f[xs:{(e_/;e∈ℝ&&e>1)...}]

Above Michael Rogers explained that I have to use (unnamed) PatternTest.

BTW: Your definition with "Real | Integer" would miss rationals, hence had to use

_Real | _Integer | _Rational
POSTED BY: Werner Geiger
Posted 2 years ago

Great, Michael. I read that restriction "... same expression ....", but did not understand it. Now I learned why and how to use PatternTest.

POSTED BY: Werner Geiger
Posted 2 years ago

Michael, just another question, concerning PatternTest for testing more than one variable.

As an example I want to match a list of 2D-vectors where y is greater than x. I can write:

MatchQ[{{1, 2}, {Pi, 3.2}}, {_?(#[[1]] < #[[2]] &) ...}]

==> True

But I cannot use a more readable form like:

MatchQ[{{1, 2}, {Pi, 3.2}}, {{_, _}?(#1 < #2 &) ...}]

==> enter image description here Do you know if there is something the like?

POSTED BY: Werner Geiger

Even though your question focused on RepeatedNull[], I maybe should have mentioned that

MatchQ[{1.1, 2., 3 + 1}, {_?(# ∈ Reals \[And] # > 1 &) ...}]

can also be done with ___ (BlankNullSequence[]) instead of ...:

MatchQ[{1.1, 2., 3 + 1}, {___?(# ∈ Reals \[And] # > 1 &)}]
POSTED BY: Michael Rogers
Posted 2 years ago

Not pattern matching, but works :

In[1]:= And @@ Map[#[[1]] < #[[2]] &, {{1, 2}, {Pi, 3.2}}]
Out[1]= True

In[2]:= And @@ Map[#[[1]] < #[[2]] &, {{1, 2}, {4, 3.2}}]
Out[2]= False
POSTED BY: Hans Milton
Posted 2 years ago

Michael, I'm glad I didn't miss anything. I agree with what you said. Your last suggestion comes closest to the "readability" goal.

Thanks again,

POSTED BY: Werner Geiger
Posted 2 years ago

I forgot to mention that I have opened another thread A pretty general pattern matching test program where I summarized the lessons learned here. I brought them into the form of a program within a notebook. The program is able to test arbitrary patterns against any arguments. Both with MatchQ and as function parameter specifications.

POSTED BY: Werner Geiger
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract