Build Your Own: User-defined Examples
Xiangdong Wen of Tech Support noted that the hard part of constructing Predicates is considering all the possible inputs and exceptions. To do a thorough job, we might need to do a Piecewise definition of a Predicate, or define a Predicate with Which, and if desired leave an error message as the final condition at the bottom to catch any exceptions that escaped us.
Limit a Built-in Predicate: lessThanOneQ
lessThanOneQ@x_ := If[ x1 < 1, True, False]
testSet = Range[0, 1.5, .3]
{0., 0.3, 0.6, 0.9, 1.2, 1.5}
lessThanOneQ /@ testSet
{True, True, True, True, False, False}
Test for Specified Length: lengthTwoQ
Clear@lengthTwoQ; lengthTwoQ@x_ := If[Length@x == 2, True, False]
lengthTwoQ /@ {{x, y}, {y, x}, {x, y, z}}
{True, True, False}
Test for Meeting Boolean Combination of Conditions: BinaryQ
By setting the Attributes of our Predicate to Listable, we shortcut the need to use Map over a List.
ClearAll@BinaryQ; SetAttributes[BinaryQ, Listable];
BinaryQ@x_ := If[x === 1 || x === 0, True, False ]
BinaryQ@{0, 3, 1, 1., 2}
{True, False, True, False, False}
One can also use Boolean And (&&) similarly, or any combination of And and Or in a compound Expression.
Test for Membership in a Set: integerLessThan10Q
Here we make a Predicate from a test for an element's membership in a defined set.
integerLessThan10 = Range@10
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
integerLessThan10Q@x_ := If[MemberQ[integerLessThan10, x], True, False]
integerLessThan10Q /@ {4, 4/5, Pi, 3, 11, 251/25}
{True, False, False, True, False, False}
More Examples: maxEqualQ, maxNearQ, valueAtQ, positionNearQ
Different Predicates can test for a variety of related conditions. These are functions I used to test properties of book bestseller lists but here I use random lists for illustration. The first one tests to see if the maximum value of two lists of numbers are the same.
maxEqualQ[x_List, y_List] := If[Max@x == Max@y, True, False]
list1 = RandomInteger[{0, 25}, 20] // Sort
{0, 2, 2, 4, 5, 6, 8, 8, 9, 9, 9, 11, 15, 16, 16, 17, 17, 19, 19, 19}
list2 = RandomInteger[{0, 25}, 20] // Sort
{1, 2, 5, 6, 6, 6, 9, 12, 13, 14, 17, 17, 18, 18, 23, 23, 24, 24, 25, 25}
maxEqualQ[list1, list2]
False
This tests to see if difference between the maximum of two lists is less than a specified magnitude.
maxNearQ[x_List, y_List, nearness_Integer] :=
If[Abs[Max@x - Max@y] <= nearness, True, False]
maxNearQ[list1, list2, 10]
True
maxNearQ[list1, list2, 1]
False
This tests to see if the Position of the maxima of two lists is the same.
maxPositionEqualQ[x_List, y_List] :=
If[Position[list1, Max@x] == Position[list2, Max@y], True, False]
maxPositionEqualQ[list1, list2]
False
Using Predicates in Select, Cases, and Related Filter Functions
As you look at these simple examples realize they are but a glimpse of the power of this type of usage that I mentioned at the start of this section. The Predicates, Conditions and Boolean conjunctions used in these filter functions can be arbitrarily complex, and as Mangone notes we are only restricted to anything that Mathematica can compute.
First we define a Predicate and use pure Function since those are idioms that Select uses, then we just use Condition in Cases, since that is the syntax that Cases uses. Consequently I recommend using the Q suffix when naming a Predicate used in Select. Note in the Cases example the additional restriction to Reals using a Head test.
Consider using Predicates in the related filter functions Count, Position, Tally, Gather, Sort, SortBy, etc.
Clear@lessThanOneQ; lessThanOneQ@x_ := If[ x < 1, True, False]
Select[Range[-0.2, 1.1, 0.2], lessThanOneQ]
{-0.2, 0., 0.2, 0.4, 0.6, 0.8}
Select[Range[-0.2, 1.1, 0.2], # < 1 &]
{-0.2, 0., 0.2, 0.4, 0.6, 0.8}
Function[x, x < 1] /@ Range[-0.2, 1.1, 0.2]
{True, True, True, True, True, True, False}
Cases[Range[-0.2, 1.1, 0.2], x_Real /; x < 1]
{-0.2, 0., 0.2, 0.4, 0.6, 0.8}
lessThanOnePositiveQ@x_ :=
If[0 < x < 1 , True, False](* version restricted to positive numbers *)
lessThanOnePositiveQv2@x_ :=
If[x < 1 && Positive@x, True, False] (* alternate version *)
Select[Range[-0.2, 1.1, 0.2], lessThanOnePositiveQ]
{0.2, 0.4, 0.6, 0.8}
Select[Range[-0.2, 1.1, 0.2], lessThanOnePositiveQv2]
{0.2, 0.4, 0.6, 0.8}
Predicate Using a Piecewise Function
Note the usage in the Named Pattern variable of a NumberQ predicate to allow both Reals and Integers. This example is intended to illustrate that a Piecewise-defined Predicate can include an unlimited number of orthogonal conditions.
Clear@pieceWiseElementQ; pieceWiseElementQ@number_?NumberQ :=
Piecewise[{{False, number < -3}, { True, -3 < number < 0}, {False,
0 <= number <= 6}, {True, number > 6}, {True, number === 4.5}}]
pieceWiseElementQ /@ {-3.00001, -0.0000000001, -4/5, 0, 0.000000001, 4/5, 4.5,
6, 6.01, 9}
{False, True, True, False, False, False, False, False, True, True}
Xiangdong Wen of Tech Support noted that the hard part of constructing Predicates is considering all the possible inputs and exceptions. To do a thorough job, we might need to do a Piecewise definition of a Predicate, or define a Predicate with Which, and if desired leave an error message as the final condition at the bottom to catch any exceptions that escaped us.
Limit a Built-in Predicate: lessThanOneQ
lessThanOneQ@x_ := If[ x1 < 1, True, False]
testSet = Range[0, 1.5, .3]
{0., 0.3, 0.6, 0.9, 1.2, 1.5}
lessThanOneQ /@ testSet
{True, True, True, True, False, False}
Test for Specified Length: lengthTwoQ
Clear@lengthTwoQ; lengthTwoQ@x_ := If[Length@x == 2, True, False]
lengthTwoQ /@ {{x, y}, {y, x}, {x, y, z}}
{True, True, False}
Test for Meeting Boolean Combination of Conditions: BinaryQ
By setting the Attributes of our Predicate to Listable, we shortcut the need to use Map over a List.
ClearAll@BinaryQ; SetAttributes[BinaryQ, Listable];
BinaryQ@x_ := If[x === 1 || x === 0, True, False ]
BinaryQ@{0, 3, 1, 1., 2}
{True, False, True, False, False}
One can also use Boolean And (&&) similarly, or any combination of And and Or in a compound Expression.
Test for Membership in a Set: integerLessThan10Q
Here we make a Predicate from a test for an element's membership in a defined set.
integerLessThan10 = Range@10
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
integerLessThan10Q@x_ := If[MemberQ[integerLessThan10, x], True, False]
integerLessThan10Q /@ {4, 4/5, Pi, 3, 11, 251/25}
{True, False, False, True, False, False}
More Examples: maxEqualQ, maxNearQ, valueAtQ, positionNearQ
Different Predicates can test for a variety of related conditions. These are functions I used to test properties of book bestseller lists but here I use random lists for illustration. The first one tests to see if the maximum value of two lists of numbers are the same.
maxEqualQ[x_List, y_List] := If[Max@x == Max@y, True, False]
list1 = RandomInteger[{0, 25}, 20] // Sort
{0, 2, 2, 4, 5, 6, 8, 8, 9, 9, 9, 11, 15, 16, 16, 17, 17, 19, 19, 19}
list2 = RandomInteger[{0, 25}, 20] // Sort
{1, 2, 5, 6, 6, 6, 9, 12, 13, 14, 17, 17, 18, 18, 23, 23, 24, 24, 25, 25}
maxEqualQ[list1, list2]
False
This tests to see if difference between the maximum of two lists is less than a specified magnitude.
maxNearQ[x_List, y_List, nearness_Integer] :=
If[Abs[Max@x - Max@y] <= nearness, True, False]
maxNearQ[list1, list2, 10]
True
maxNearQ[list1, list2, 1]
False
This tests to see if the Position of the maxima of two lists is the same.
maxPositionEqualQ[x_List, y_List] :=
If[Position[list1, Max@x] == Position[list2, Max@y], True, False]
maxPositionEqualQ[list1, list2]
False
Using Predicates in Select, Cases, and Related Filter Functions
As you look at these simple examples realize they are but a glimpse of the power of this type of usage that I mentioned at the start of this section. The Predicates, Conditions and Boolean conjunctions used in these filter functions can be arbitrarily complex, and as Mangone notes we are only restricted to anything that Mathematica can compute.
First we define a Predicate and use pure Function since those are idioms that Select uses, then we just use Condition in Cases, since that is the syntax that Cases uses. Consequently I recommend using the Q suffix when naming a Predicate used in Select. Note in the Cases example the additional restriction to Reals using a Head test.
Consider using Predicates in the related filter functions Count, Position, Tally, Gather, Sort, SortBy, etc.
Clear@lessThanOneQ; lessThanOneQ@x_ := If[ x < 1, True, False]
Select[Range[-0.2, 1.1, 0.2], lessThanOneQ]
{-0.2, 0., 0.2, 0.4, 0.6, 0.8}
Select[Range[-0.2, 1.1, 0.2], # < 1 &]
{-0.2, 0., 0.2, 0.4, 0.6, 0.8}
Function[x, x < 1] /@ Range[-0.2, 1.1, 0.2]
{True, True, True, True, True, True, False}
Cases[Range[-0.2, 1.1, 0.2], x_Real /; x < 1]
{-0.2, 0., 0.2, 0.4, 0.6, 0.8}
lessThanOnePositiveQ@x_ :=
If[0 < x < 1 , True, False](* version restricted to positive numbers *)
lessThanOnePositiveQv2@x_ :=
If[x < 1 && Positive@x, True, False] (* alternate version *)
Select[Range[-0.2, 1.1, 0.2], lessThanOnePositiveQ]
{0.2, 0.4, 0.6, 0.8}
Select[Range[-0.2, 1.1, 0.2], lessThanOnePositiveQv2]
{0.2, 0.4, 0.6, 0.8}
Predicate Using a Piecewise Function
Note the usage in the Named Pattern variable of a NumberQ predicate to allow both Reals and Integers. This example is intended to illustrate that a Piecewise-defined Predicate can include an unlimited number of orthogonal conditions.
Clear@pieceWiseElementQ; pieceWiseElementQ@number_?NumberQ :=
Piecewise[{{False, number < -3}, { True, -3 < number < 0}, {False,
0 <= number <= 6}, {True, number > 6}, {True, number === 4.5}}]
pieceWiseElementQ /@ {-3.00001, -0.0000000001, -4/5, 0, 0.000000001, 4/5, 4.5,
6, 6.01, 9}
{False, True, True, False, False, False, False, False, True, True}