1
$\begingroup$

I implemented the following routine.

array1 = {12, -12, 14, 12, 1, -3, 1, 1, 2, 7, 8, 102, 2, 3, 3, 1, 332,
11, 23, 2, -2, 13, 12, 1, 1, 1, 1, 1, 1, -121, 131};

I want to find sublists which consist of consecutive numbers which absolute values are smaller than a certain treshold (Lim=5). I also want to have a parameter for the length of the sublists (Len=3).

Module[{Ar, Pos, Lim, Len},
 Ar = #;
 Lim = 5;
 Len = 3;
 Position[Ar, x_ /; Abs[x] < Lim] // Flatten[#] & // Set[Pos, #] &;
 Select[Split[Pos, #2 - #1 == 1 &], Length[#] > Len &]
 ] &[array1] // Set[PosInt, #] &;

Now I have the positions of the sublists.

PosInt // Print;
{{5,6,7,8,9},{13,14,15,16},{24,25,26,27,28,29}}

The next thing I would like to have is an array which includes the number and the position of the sublists. I have the following solution.

array2 = ConstantArray[0, Length@array1];
Module[{IntNum, Num, Pos},
Pos = #;
MapIndexed[(
   IntNum = First@#2;
   Num = #1;
   Map[(array2[[#]] = IntNum
      ) &, Num];
   ) &, Pos]
] &[PosInt];

The desired result is saved as array2.

array2 // Print;
{0,0,0,0,1,1,1,1,1,0,0,0,2,2,2,2,0,0,0,0,0,0,0,3,3,3,3,3,3,0,0}

My implementation yields the right result. Nevertheless I'm sure it is possible to find a more elegant solution. Do you have any suggestions?

$\endgroup$
  • 2
    $\begingroup$ Are you aware that in Mathematica expression standing by itself on a line at top-level is essentially the same as expression // Print;? $\endgroup$ – m_goldberg Jan 14 at 8:12
  • $\begingroup$ @m_goldberg Thx for your comment. You are right, that's superfluous. $\endgroup$ – RMMA Jan 14 at 8:18
  • 1
    $\begingroup$ But the first position smaller than 5 is for -12 which is 2 right then why it starts with 5 in the position list {5,6,7,8,9} $\endgroup$ – Hubble07 Jan 14 at 9:32
  • $\begingroup$ @Hubble07 Thank you! The absolute Number Abs[] has to be smaller. I did edit the question. $\endgroup$ – RMMA Jan 14 at 9:40
  • $\begingroup$ One more doubt. What about position 20 and 21. I mean what if the after taking absolute value we get two same numbers. $\endgroup$ – Hubble07 Jan 14 at 9:45
2
$\begingroup$

Currently, I address only your first problem. This is not really Mathematica-like but about 250 times faster than your approach.

Here is the CompiledFunction that I use; It goes linearly through the list and collects starting and ending index of each run in a Internal`Bag.

cf = Compile[{{a, _Integer, 1}, {Lim, _Integer}, {Len, _Integer}},
   Block[{c, bag, x, α},
    α = 0;
    c = 0;
    bag = Internal`Bag[Most[{0}]];
    Do[
     x = Compile`GetElement[a, i];
     If[Abs[x] < Lim,
      If[c == 0, α = i;];
      c++;
      ,
      If[c > Len,
       Internal`StuffBag[bag, α];
       Internal`StuffBag[bag, i - 1];
       ];
      c = 0;
      ],
     {i, 1, Length[a]}];
    Partition[Internal`BagPart[bag, All], 2]
    ],
   CompilationTarget -> "C",
   RuntimeOptions -> "Speed"
   ];

Here is your method in a (IMHO) more legible form:

f = {a, Lim, Len} \[Function] Select[
    Split[Flatten[Position[a, x_ /; Abs[x] < Lim]], #2 - #1 == 1 &],
    Length[#] > Len &
    ];

Let's create a large array of pseudorandom integers and run the two functions on it:

a = RandomInteger[{-10, 10}, {1000000}];

PosInt = f[a, Lim, Len]; // AbsoluteTiming // First
PosInt2 = cf[a, Lim, Len]; // RepeatedTiming // First

The output of cf is slightly different from that of f; it returns only the first and last position index of each desired sublist. So we can compare the results in either of the two follwoing ways:

PosInt[[All, {1, -1}]] == PosInt2
PosInt == Range @@@ PosInt2

True

True

$\endgroup$
  • $\begingroup$ Thank you for your answer. Until now I didn't use CompiledFunction at all. Maybe I should start using, your impelementation of AppendTo is very useful as well. $\endgroup$ – RMMA Jan 14 at 13:05
  • $\begingroup$ You're welcome. $\endgroup$ – Henrik Schumacher Jan 14 at 13:35

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.