I have a list of boolean functions {f1, f2, f3, ...} that take a value and return True or
False. They are used to check whether the value meets certain conditions.
I need to run construct a nested If statement that for an arbitrary value sequentially evaluates the boolean functions above and returns True if all functions return True, and False otherwise :
If[f1[#],
If[f2[#],
If[f3[#],
True,
False],
False],
False]
It is important that this evaluation is sequetial, so that f1 is evaluated before f2, f2 before f3 etc.; and that as soon as any of the functions returns False, the entire evaluation stops. This is necessary because each evaluation is time-consuming, and I don't want to evaluate any other functions once one of them returns False.
I wrote the following function to generate the nested if statement:
NestedIf[conds_] := Function[d, Fold[If[#2[d], #1, False] &, True, Reverse@conds]];
And use it within Select statement to pick out the values from my dataset that meet all of the conditions f1,f2,f3, etc.:
Select[data, NestedIf[{f1, f2, f3}]]
However, the problem with this function is that once I pass it a value, it first evaluates all conditions and only then inserts them into the nested If structure. So I get no time savings.
I tried using SetAttributes[NestedIf,HoldAll], but that did not help because the arguments are still evaluated first.
How can I prevent the arguments from being evaluated prematurely?
P.S. AllTrue command does something very similar to what I want, by sequentially checking if all values in a list satisfies one test. What I need is to test whether one value satisfies a list of tests.
P.P.S. Several people have suggested using And for sequential evaluation. Unfortunately the problem is that all the arguments ends up being evaluated before And begins sequential evaluation. For example, try running this:
f1[x_] := (Print["First"]; x > 10);
f2[x_] := (Print["Second"]; x > 20);
And[Through[{f1, f2}[#]]] & @ 5
The output will be:
First
Second
{False, False}
So both arguments are evaluated before they are passed to And, and I'm trying to find a way to prevent that.
Which[]andAllTrue[]andAnd[]. – David G. Stork Apr 07 '15 at 21:04AllTrue, but it solves a somewhat different problem (one test for a list of values, instead of a list of tests for one value).Whichdoesn't seem to allow for sequential evaluation of tests based on the results of previous tests, andAndevaluates all tests at the same time rather than sequentially. – verse Apr 07 '15 at 21:10Andwill evaluate its arguments sequentially, returningFalseas soon as any argument isFalse. – Simon Woods Apr 07 '15 at 21:19And[# > 5 & @ #, # < 7 & @ #] & @ 6True andAnd[# > 5 & @ #, # < 7 & @ #, # < 4 & @ #] & @ 6False. – David G. Stork Apr 07 '15 at 21:19niF[conds__] := Function[x, And @@ Through@{conds}@x, Listable]? – kglr Apr 07 '15 at 21:51Anditself doesn't evaluate arguments sequentially, but that by the time it starts sequential evaluation, all arguments have already been evaluated.Through@{conds}@xevaluates all arguments before passing them toAnd– verse Apr 08 '15 at 00:02AndisAnd[arg1, arg2, arg3]and notAnd[{arg1, arg2, arg2}]. Observe:And[Print[1]; False, Print[2]; False], more conveniently written as(Print[1]; False) && (Print[2]; False). The second argument never gets evaluated. – Szabolcs Apr 08 '15 at 00:18