I want to check if a data set of size $10^{10}$ contains any non-positive elements. Positive[Name of dataset]
returns a list of True
and False
of length $10^{10}$. I want only a single True
if all terms of that dataset are positive and False
otherwise.
4 Answers
$\begingroup$
$\endgroup$
4
Alternate solution:
list = RandomReal[1, 10^6];
Min[list] >= 0
-
3$\begingroup$ ...i.e.
NonNegative[Min[list]]
. $\endgroup$ Commented Mar 27, 2019 at 16:08 -
3$\begingroup$ Very good solution! This avoids lists of Booleans and hence allows for vectorization. (Boolean arrays cannot be packed.) $\endgroup$ Commented Mar 27, 2019 at 18:01
-
2$\begingroup$ This is about 100 times faster than any of the other solutions. Impressive! $\endgroup$– RomanCommented Mar 27, 2019 at 20:03
-
$\begingroup$
$\endgroup$
8
Since you have a very large list, you should look at the timing
list = RandomReal[1, 10^6];
(And @@ Positive[list]) // AbsoluteTiming (* Hanlon *)
(* {0.050573, True} *)
VectorQ[list, Positive] // AbsoluteTiming (* J.M. *)
(* {0.261642, True} *)
(AnyTrue[list, Negative] // Not) // AbsoluteTiming (* Morbo *)
(* {0.324062, True} *)
And @@ (list /. {x_?Negative -> False,
x_?Positive -> True}) // AbsoluteTiming (* Alrubaie *)
(* {1.00664, True} *)
EDIT: As suggested by mjw, encountering a nonpositive value early in the list significantly alters the results.
list2 = ReplacePart[list, 1000 -> -1];
(And @@ Positive[list2]) // AbsoluteTiming (*Hanlon*)
(* {0.277642, False} *)
VectorQ[list2, Positive] // AbsoluteTiming (*J.M.*)
(* {0.000223, False} *)
(AnyTrue[list2, Negative] // Not) // AbsoluteTiming (*Morbo*)
(* {0.000262, False} *)
And @@ (list2 /. {x_?Negative -> False,
x_?Positive -> True}) // AbsoluteTiming (*Alrubaie*)
(* {1.43026, False} *)
-
$\begingroup$ Looks like your method is five times faster than the next best! Can you give some insight into why this is? Thanks! $\endgroup$– mjwCommented Mar 27, 2019 at 15:34
-
1$\begingroup$ Also, and I guess this depends on the probability of any entry being negative, it may make sense for the algorithm to stop as soon as it finds a negative (or non-positive) element in the list. $\endgroup$– mjwCommented Mar 27, 2019 at 15:37
-
1$\begingroup$ @mjw,
And[]
does short-circuit evaluation. $\endgroup$ Commented Mar 27, 2019 at 15:41 -
1$\begingroup$ @Bob, Thank you for your edit. Why, though, does it take longer for your method to work when there is a negative entry? I would have thought that in each case, it would take the same amount of time to go through the whole list. $\endgroup$– mjwCommented Mar 27, 2019 at 16:03
-
1$\begingroup$ @Roman, I do not believe that any lazy evaluation is being done. My comment was more to point out that an evaluation like
And[True, True, False, True, True, ... True]
will finish at once (and similar remarks apply forOr[]
). Perhaps one can judiciously useCatch[]/Throw[]
if an early-return test for long lists is desired. $\endgroup$ Commented Mar 27, 2019 at 16:06
$\begingroup$
$\endgroup$
4
Ah, maybe this is too simple, but works for exactly what you're doing:
data = Table[RandomReal[{-1,1}],{i,1,1000}];
AnyTrue[data,Negative] // Not
(*False*)
data2 = Table[RandomReal[], {i, 1, 10^2}];
AnyTrue[data2, Negative] // Not
(*True*)
-
$\begingroup$
AllTrue[data, Positive]
to get the sign right. Or useNot
on your solution. $\endgroup$– RomanCommented Mar 27, 2019 at 14:55 -
$\begingroup$ @Roman - the poster is using
AnyTrue
notAllTrue
$\endgroup$ Commented Mar 27, 2019 at 15:00 -
1$\begingroup$ Yes @BobHanlon . In order to invert his solution to what the OP wants you have to either
Not@AnyTrue[data,Negative]
or (simpler)AllTrue[data,Positive]
orAllTrue[data,NonNegative]
. $\endgroup$– RomanCommented Mar 27, 2019 at 15:04 -
$\begingroup$ ah, signs are reversed, missed that part. I updated the code to reflect questioners exact question. $\endgroup$ Commented Mar 27, 2019 at 15:04
$\begingroup$
$\endgroup$
0
list = {1, 2, 3, 4, -5, -6, -7};
list /. {x_?Negative -> True, x_?Positive -> False}
VectorQ[list, Positive]
? $\endgroup$Apply
as inAnd @@ Positive[list]
$\endgroup$Positive
), or do you need all terms to be zero or positive (useNonNegative
)? $\endgroup$