4
$\begingroup$

I have a set of positions where I want to slice a list of numbers. If I Total the values in that list, and they are greater than or equal to 1, I want to remember the coordinates of the slice.

The following function implements the above, but when If evaluates to False, and empty list is appended to the coordinates I wanted to remember.

I understand it is possible to just simply remove the empty lists after the whole data structure is assembled, but I do not want to do this. The reason is that I am dealing with very large data sets and want to minimize the number of unnecessary operations. With this in mind, it would be ideal if the empty list was never appended in the first place. Link to Similar Question

 tstFunc[pos_, lst_] := 
    Module[{realPulses = {}, start = pos[[1]], stop = pos[[2]], tot = 0}, 
      tot = Total[ lst[[start ;; stop]] ];
      If[tot >= 1, 
        realPulses = Flatten[Append[realPulses, pos]]];
     realPulses]


  pos = {{1, 5}, {10, 11}, {15, 20}}
  highArray = SparseArray[# -> 1 & /@ {4, 5, 10, 11}, 20]

  highSlices = tstFunc[#, highArray] & /@ pos

Gives Output

   {{1, 5}, {10, 11}, {}}

I have taken the answers so far and compared their timing, since I tagged the question with timing.

 AbsoluteTiming[tstFuncEldo[pos, highArray]]

 {0.000237271, {{1, 5}, {10, 11}}}


 AbsoluteTiming[tstFuncGeorge[#, highArray] & /@ pos]
 {0.000286419, {{1, 5}, {10, 11}}}

 AbsoluteTiming[tstFuncXavier[#, highArray] & /@ pos]
 {0.000388954, {{1, 5}, {10, 11}}}

Can any one comment as to why my 'If' statement is appending an empty list?


Note: @eldo solution is the only one that gives the correct result for pos = {{11,22}, {270, 270}, {291, 291}}

$\endgroup$
7
  • $\begingroup$ I guess highArray should be list ? $\endgroup$
    – george2079
    Dec 11, 2015 at 20:17
  • $\begingroup$ Perhaps you will find the alternative function tstFunc2[pos_, lst_] := If[Plus @@ Take[lst, pos] >= 1, pos, Unevaluated@Sequence[]]; useful for "minimiz[ing] the number of unnecessary operations". $\endgroup$
    – user31159
    Dec 11, 2015 at 20:20
  • $\begingroup$ @george2079 Thanks for this. highArray is a sparse array. Now I have edited. $\endgroup$
    – olliepower
    Dec 11, 2015 at 21:43
  • $\begingroup$ @Xavier I tried your function and it did not work for me. I must be putting in the arguments in correctly. $\endgroup$
    – olliepower
    Dec 11, 2015 at 22:04
  • 1
    $\begingroup$ Take[list,{a,b}] and list[[{a,b}]] are not the same. Take is what you want here... (the latter happens to give the same result for this example) $\endgroup$
    – george2079
    Dec 12, 2015 at 14:03

3 Answers 3

4
$\begingroup$
list = SparseArray[# -> 1 & /@ {4, 5, 10, 11}, 20];

pos = {{1, 5}, {10, 11}, {15, 20}};

tstFunc[pos_, lst_] := 
   Pick[pos, Sign@Total@lst[[Span@##]] & @@@ pos, 1]

tstFunc[pos, list]

{{1, 5}, {10, 11}}

$\endgroup$
8
  • $\begingroup$ So far yours is the fastest eldo. Very clever solution to, avoiding If all together. $\endgroup$
    – olliepower
    Dec 11, 2015 at 22:45
  • $\begingroup$ Or, Pick[pos, Sign[Total[list[[#]] & /@ pos, {2}]], 1]. $\endgroup$ Dec 12, 2015 at 11:06
  • $\begingroup$ @eldo I noticed the tstFunc here has a bug in a special case, where pos has an element that looks like {2,2}', indicating that we should only look at position 2` in high array, and evaluate that there is a '1' in that position. i'm not sure how to fix it. $\endgroup$
    – olliepower
    Dec 14, 2015 at 23:07
  • $\begingroup$ Do you have this problem also with the other solutions? Could you supply your definitions of list and pos which cause the problem? $\endgroup$
    – eldo
    Dec 14, 2015 at 23:14
  • $\begingroup$ list = SparseArray[# -> 1 & /@ {12, 13, 14, 15, 16, 17, 18, 19}, 302] $\endgroup$
    – olliepower
    Dec 14, 2015 at 23:19
3
$\begingroup$

Just some variants:

First@GatherBy[pos, Total@list[[#]] > 0 &]
True /. GroupBy[pos, Total@list[[#]] > 0 &]
Join @@ Last@Reap[Sow[#, Total@list[[#]]] & /@ pos, _?(# > 0 &), #2 &]
$\endgroup$
2
$\begingroup$

As an answer to the literal question, you need to return an empty sequence.

tstFunc[pos_, lst_] :=
 Module[{realPulses = {}, start = pos[[1]], stop = pos[[2]], tot = 0},
  tot = Total[lst[[start ;; stop]]]; 
  If[tot >= 1, pos, Unevaluated@Sequence[]]]

highSlices = tstFunc[#, list] & /@ pos

{{1, 5}, {10, 11}}

Of course if you find yourself doing this it likely means you didnt want to use Map in the first place.

$\endgroup$
1
  • 4
    $\begingroup$ Note that as of 10.2 we can use Nothing in place of Unevaluated@Sequence[] $\endgroup$ Dec 11, 2015 at 20:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.