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$
  • $\begingroup$ I guess highArray should be list ? $\endgroup$ – george2079 Dec 11 '15 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 '15 at 20:20
  • $\begingroup$ @george2079 Thanks for this. highArray is a sparse array. Now I have edited. $\endgroup$ – olliepower Dec 11 '15 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 '15 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 '15 at 14:03
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}}

| improve this answer | |
$\endgroup$
  • $\begingroup$ So far yours is the fastest eldo. Very clever solution to, avoiding If all together. $\endgroup$ – olliepower Dec 11 '15 at 22:45
  • $\begingroup$ Or, Pick[pos, Sign[Total[list[[#]] & /@ pos, {2}]], 1]. $\endgroup$ – J. M.'s technical difficulties Dec 12 '15 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 '15 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 '15 at 23:14
  • $\begingroup$ list = SparseArray[# -> 1 & /@ {12, 13, 14, 15, 16, 17, 18, 19}, 302] $\endgroup$ – olliepower Dec 14 '15 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 &]
| improve this answer | |
$\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.

| improve this answer | |
$\endgroup$
  • 4
    $\begingroup$ Note that as of 10.2 we can use Nothing in place of Unevaluated@Sequence[] $\endgroup$ – Simon Woods Dec 11 '15 at 20:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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