As a simple example of what I would like to do, suppose I have a list a
of all real numbers. I would like to perform a simple check to see if some element of a
is positive. Of course, I could do this with a simple loop, but I feel as if Mathematica would have a more efficient way of doing this, in the spirit of functional programming. Is there, or do I just have to do this with a clumsy loop:
test=False; For[counter=1;counter<=Length[a];counter++;If[a[[counter]]>0,test=True;];];
Answer
If I understand you correctly, simply test if the maximum value in the list is Positive:
Positive @ Max @ a
Speed comparison with other methods that were posted:
timeAvg =
Function[func,
Do[If[# > 0.3, Return[#/5^i]] & @@ Timing@Do[func, {5^i}], {i, 0, 15}],
HoldFirst];
a = RandomInteger[{-1*^7, 2}, 1*^7];
MemberQ[a, _?Positive] // timeAvg
Total@UnitStep[-a] =!= Length@a // timeAvg
Positive@Max@a // timeAvg
0.593
0.0624
0.01148
Early-exit methods
Although very fast, especially with packed lists, the method above does scan the entire list with no possibility for an early exit when a positive elements occurs near the front of the list. In that case a test that does not scan the entire list may be faster, such as the one that R.M posted. Exploring such methods I propose this:
! VectorQ[a, NonPositive]
Unlike MemberQ
, VectorQ
does not unpack a packed list.
Timings compared to MemberQ
and Max
, first with an early positive appearance:
SeedRandom[1]
a = RandomReal[{-1*^7, 1000}, 1*^7];
Positive @ Max @ a // timeAvg
! VectorQ[a, NonPositive] // timeAvg
MemberQ[a, _?Positive] // timeAvg
0.008736
0.00013984
0.2528
(Most of the MemberQ
time is spent unpacking the list.)
Then no positive appearance (full scan):
a = RandomInteger[{-1*^7, 0}, 1*^7];
Positive @ Max @ a // timeAvg
! VectorQ[a, NonPositive] // timeAvg
MemberQ[a, _?Positive] // timeAvg
0.01148
1.544
2.528
Finally a mid-range appearance of a positive value in an unpacked list:
a = RandomReal[{-50, 0}, 1*^7];
a[[5*^6]] = 1;
Positive @ Max @ a // timeAvg
! VectorQ[a, NonPositive] // timeAvg
MemberQ[a, _?Positive] // timeAvg
0.212
0.702
1.045
Comments
Post a Comment