@Nasser's FirstCase
gets my vote for speed and simplicity, but different methods will work faster depending on where the first positive first element could show up. Compare the different approaches in this thread along with a new function using Throw
and Catch
in a Do
loop:
firstcase[list_] := FirstCase[list, x_ /; Positive[First[x]]] (* Nasser *)
select[list_] := Select[list, First@*Positive, 1][[1]] (* m_goldberg *)
selfirst[list_] := SelectFirst[list, #[[1]] > 0 &] (* ercegovac *)
pick[list_] := Pick[#, Sign[#[[All, 1]]], 1][[1]] &@list (* tomd *)
lenwhile1[list_] := list[[1 + LengthWhile[list[[All, 1]], # <= 0 &]]]; (* kglr *)
lenwhile2[list_] := list[[1 + LengthWhile[list, #[[1]] <= 0 &]]]; (* kglr *)
throwcatch[list_] := Catch@Do[If[list[[i, 1]] > 0, Throw[list[[i]]]], {i, Length[list]}]
on two lists:
SeedRandom[1]
T1 = RandomInteger[{-5, -1}, {100000, 3}]~Join~{{2, 4, 4}}; (* The "hard" problem *)
T2 = RandomInteger[{-5, 5}, {100000, 3}]; (* The "easy" problem *)
Obviously the first list is "harder", but there are interesting performance differences between the different functions:
functions = {firstcase, select, selfirst, pick, lenwhile1, lenwhile2, throwcatch};
res = Map[{First@AbsoluteTiming[#[T1]], First@AbsoluteTiming[#[T2]]} &, functions]
TextGrid[Join[{{"", "T1", "T2"}}, Transpose[
Join[{{"firstcase", "select", "selfirst", "pick", "lenwhile1", "lenwhile2", "throwcatch"}},
Transpose[res]]]]] // TeXForm
\begin{array}{l|l|l}
\text{} & \text{T1} & \text{T2} \\
\hline
\text{firstcase} & 0.104779 & 0.0229505 \\
\text{select} & 0.177957 & 0.0214707 \\
\text{selfirst} & 0.12791 & 0.0221214 \\
\text{pick} & 0.00207038 & 0.00345685 \\
\hline
\text{lenwhile1}^* & 0.0588038 & 0.00159609 \\
\text{lenwhile2}^* & 0.129428 & 0.0000127513 \\
\text{throwcatch} & 0.108226 & 0.0000205265 \\
\end{array}
${}^*$ Apparently @kglr's LengthWhile
-based functions run slower on my machine. The free browser version of Mathematica 11.2 gets the timings for lenwhile1 /@ {T1, T2}
to be {0.04873300, 0.00145900}
and for lenwhile2 /@ {T1, T2}
to be {0.09734200, 3.0*10^-6}
. The timings above were obtained on Mathematica 11.2 running ion Win10.
The advantage of the LengthWhile
and Throw
/Catch
methods on the easy problem presumably comes from the fact that they explicitly exit when the result is found, although I have no idea how FirstCase
and SelectFirst
actually work, so they may be doing a similar thing. pick
outperforms everything else by an order of magnitude on the hard problem, but for reasons which baffle me, actually takes longer on the easy problem. (throwcatch
can also be Compile
d, which increases its speed by another order of magnitude on the easy problem, and two orders of magnitude on the hard problem.)
All of which is just to say that knowing a little about the structure of the problem can help make a choice about the best algorithm to tackle it. Of course, in the OP's example there were only 30 elements, so all this is kind of moot...
SelectFirst[T, #[[1]] > 0 &]
which gives (Out[1]={2, 4, 4}
). $\endgroup$Pick[#, Sign[#[[All, 1]]], 1][[1]] &@T
$\endgroup$