positions satisfying pattern and grouped - Mathematica Stack Exchange most recent 30 from mathematica.stackexchange.com 2019-09-23T09:56:41Z https://mathematica.stackexchange.com/feeds/question/110856 https://creativecommons.org/licenses/by-sa/4.0/rdf https://mathematica.stackexchange.com/q/110856 4 positions satisfying pattern and grouped leosenko https://mathematica.stackexchange.com/users/27123 2016-03-23T20:55:34Z 2016-03-24T02:21:10Z <p>I have a list of numbers and I am looking for a way to most efficiently find positions of values that satisfy a certain condition and group those positions that are sequential. To illustrate, a simple list can look like</p> <pre><code>x={1,2,4,6,2,3,4,5,7,9,1,3,4,1} </code></pre> <p>and I am interested in all numbers that are greater than 2 and so I expect the return to look like:</p> <pre><code>res={{3,4},{6,7,8,9,10},{12,13}} </code></pre> <p>Alternatively, I would also need the result being the values in <code>x</code> however grouped in the same manner.</p> <p>The stress is also on effectivness, this will be applied on a number of 100 MB data files. My initial idea was: <code>Position[x, n_ /; n &gt; 50] // Flatten</code> and then somehow go through the output and determined if the next position is previous plus 1 but I think this is not very effective (also I have no idea how to do it without complex loops).</p> https://mathematica.stackexchange.com/questions/110856/-/110868#110868 2 Answer by Leonid Shifrin for positions satisfying pattern and grouped Leonid Shifrin https://mathematica.stackexchange.com/users/81 2016-03-23T21:47:33Z 2016-03-23T21:54:25Z <p>You can use the <code>BoolEval</code> function from the <a href="http://www.packagedata.net/index.php/links/examples/id/31" rel="nofollow">BoolEval</a> package. You can load it as follows, for example:</p> <pre><code>Import["https://bitbucket.org/szhorvat/booleval/raw/8e1eaf980500b5ff066b2b4bf3a61c1ad2e9c02d/BoolEval.m"] </code></pre> <p>Here is a function based on that:</p> <pre><code>ClearAll[getSplitPositions]; SetAttributes[getSplitPositions, HoldRest]; getSplitPositions[list_, crit_] := With[{pos = Sort@Pick[Range[Length[list]], BoolEval[ crit], 1]}, If[pos === {}, Return[{}]]; Internal`PartitionRagged[ pos, Composition[ Append[#, Length[pos] - Total[#]] &amp;, Differences, Prepend, Flatten, #["NonzeroPositions"] &amp;, SparseArray, Unitize, Differences@# - 1 &amp; ] @ pos ] ]; </code></pre> <p>It does reproduce you desired output:</p> <pre><code>list = {1, 2, 4, 6, 2, 3, 4, 5, 7, 9, 1, 3, 4, 1}; getSplitPositions[list, list &gt; 2] (* {{3, 4}, {6, 7, 8, 9, 10}, {12, 13}} *) </code></pre> <p>And it can handle a list of million numbers in a fraction of a second:</p> <pre><code>lrgTest = RandomInteger[{1, 1000}, 1000000]; getSplitPositions[lrgTest, 250 &lt; lrgTest &lt; 300] // Length // AbsoluteTiming (* {0.178297, 46292} *) </code></pre> <p>It does, however, have an issue - it unpacks, presumably due to certain subtleties of the <code>BoolEval</code> implementation. Here is a version of <code>BoolEval</code> that won't unpack:</p> <pre><code>ClearAll[BoolEval]; SetAttributes[BoolEval, HoldAll]; BoolEval[condition_] := Replace[ Unevaluated[condition], BoolEval`Private`rules, {0, Infinity}, Heads -&gt; True ] </code></pre> <p>In this particular case, the speed is the same, but the memory use should probably be better with this version. </p> https://mathematica.stackexchange.com/questions/110856/-/110892#110892 0 Answer by Algohi for positions satisfying pattern and grouped Algohi https://mathematica.stackexchange.com/users/13548 2016-03-24T02:21:10Z 2016-03-24T02:21:10Z <pre><code>Clear[g] g[list_, limit_] := Module[{l, l2}, l = (list - limit); l2 = Unitize[l] UnitStep[l] Range[Length[list]]; Split[l2, #1 != 0 &amp;&amp; #2 != 0 &amp;] /. {0} -&gt; Sequence[]]; g[x, 2] (*{{3, 4}, {6, 7, 8, 9, 10}, {12, 13}}*) </code></pre> <p>Testing it with <a href="https://mathematica.stackexchange.com/users/81/leonid-shifrin">Leonid Shifrin </a>(with only one limit):</p> <pre><code>g[lrgTest, 250] // Length // AbsoluteTiming (*{1.25263, 187504}*) </code></pre>