4
$\begingroup$

I'm trying to make calculations on a list that depend on the previous value. In my case I'm doing event detection - detecting the point where a value rises above some threshold for the first time

e.g.

list[t]=SomeFunction[list[t-1] ];

A perfect general example would be calculating a fibonacci number non-recursively.

fib[0]=0
fib[1]=1
fib[n]= fib[n-1]+fib[n-2]

If my function just took the value at t I could simply use Map. But I need to work with the value at t-1.

What's the right (functional/mathematica) way to do this? I'm sure there's a way built into mathematica for this, I'm just not finding it in the documentation.

stream = {1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2, 1};
stream[[6]] > 5 &&  stream[[5]] <= 5

Update: Expanding from my concrete example a bit. There are many algorithms and formula, which rely on e.g. the previous or n-1 values in their calculation.

Map is a very simple way to transform a list by a function. Is there an equivalent, elegant, method to do the same where the function may need previous (or n-1, neighbouring) values?

A perfect general example would be calculating a fibonacci number non-recursively.

fib[0]=0
fib[1]=1
fib[n]= fib[n-1]+fib[n-2]
$\endgroup$

3 Answers 3

3
$\begingroup$

Many ways (for example MapIndexed[]) but you may have some fun using for example @Leonid's implementation of FoldWhile[] here

stream = {0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2, 1}; 
FoldWhile[#2 &, ! (#1 <= 5 && #2 > 5) &, 0, stream]
(* 5 *)

Here is how it works:

Grid @@@ Reap@
  FoldWhile[(Sow[{"Current", #2, " ", "Previous", #1}]; #2) &, ! (#1 <= 5 && #2 > 5) &, 18, stream]

Mathematica graphics

$\endgroup$
2
$\begingroup$

Perhaps

stream = {1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2, 1};

LengthWhile[stream, # <= 5 &]
(* 5 *)
TakeWhile[stream, # <= 5 &]
(* {1,2,3,4,5} *)

or

First[Split[stream , #1 < 5 &]]
(* {1,2,3,4,5} *)
Length@First@Split[stream , #1 < 5 &]
(* 5 *)

or

i = 1; While[stream[[i]] < 5, i++]; i
(* 5 *)
i = 1; While[stream[[i]] < 5, i++]; stream[[;; i]]
(* {1,2,3,4,5} *)

or

(* foo @@@ Transpose[{Most@stream , Rest@stream}] *)
Boole[# <= 5 < #2] & @@@ Transpose[{Most@stream , Rest@stream}]
(* {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} *)
$\endgroup$
0
$\begingroup$

I am not sure what it is you are trying to do, but presumably list = foo /@ RotateRight[list] is something like what you want?!

The most general solution involves the function ListConvolve[] which you should look up (the documentation gives you better examples than the ones I can come up with without knowing what it is you want to do). You want the second last usage (replacing Plus and Times with functions of your own).

$\endgroup$
3
  • 3
    $\begingroup$ Aside from a serious typo that's rather a comment than an answer. Why don't you show the output of your construction? $\endgroup$
    – eldo
    Sep 19, 2014 at 18:35
  • $\begingroup$ That's essentially the same as Map. Another way to phrase what I'm looking for would be Mapping a list, which allows my function to look up other values in the list, rather than just the value it's working on. $\endgroup$
    – user4860
    Sep 19, 2014 at 18:41
  • $\begingroup$ RotateRight has the effect of looking up an adjacent value. RotateLeft would look up the value from the other side. Do you want more general lookup? $\endgroup$
    – Igor Rivin
    Sep 19, 2014 at 18:45

Your Answer

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