6
$\begingroup$

I am trying to improve some pieces of coding I use frequently and am stuck with the following. I suspect there is a very similar answer but was unable to find it.

Function fun with 3 arguments "walks" over three lists of equal length (contained in sp). The 4th argument a is the value of the function in the last step. Essentially, I want to MapThread at position I across the length of the lists while also using the last evaluation. I tried to use Fold or Nest together with Reap/Sow but to no avail. The output is the evaluation of the function, and a working example with a Do loop is as follows.

sp = RandomInteger[{1, 10}, {3, 10}]
fun[{x_, y_, z_, a_}] := 2 x - y + 3 z - 2 a
atposI = 0; lastval := 0; output := {};

Do[{
atposI = Append[sp[[All, i]], lastval];
lastval = fun[atposI];
output = Append[output, lastval]
}, {i, 1, 10}]
output

Input:

{{7, 1, 5, 10, 10, 2, 5, 10, 10, 6}, {4, 1, 4, 2, 5, 2, 2, 4, 8, 10}, {2, 6, 1, 4, 6, 7, 4, 1, 2, 8}}

Result

{16, -13, 35, -40, 113, -203, 426, -833, 1684, -3342}

I am particularly interested in solutions that contain Fold, Nest and Reap/Sow, although any answer is more than welcome.

$\endgroup$
1
  • $\begingroup$ FoldPairList does this, or similar enough, if I understand your question right. $\endgroup$
    – Roman
    May 5, 2020 at 17:41

3 Answers 3

3
$\begingroup$

An alternative to FoldList could be FoldPairList:

FoldPairList[
  Function[{prev, new}, {#, #}&@ ({2, -1, 3}.new - 2 prev) ],
  0,
  Transpose@sp
]

(* {16, -13, 35, -40, 113, -203, 426, -833, 1684, -3342} *)

In response to the request of keeping function fun definition, you can modify the above to obtain the same result as follows:

ClearAll[fun]
fun[{x_, y_, z_, a_}] := 2 x - y + 3 z - 2 a

FoldPairList[
  Function[{prev, new}, {#, #}&@ fun[{Sequence @@ new, prev}]],
  0,
  Transpose@sp
]
$\endgroup$
2
  • $\begingroup$ Many thanks for your answer. As I commented to another post, is it possible to retain function fun "as is" in the code and not rely on it being linear and use the coefficients? $\endgroup$
    – Titus
    May 5, 2020 at 19:00
  • 1
    $\begingroup$ @Titus Sure, although it may be a bit awkward-looking. See edit. $\endgroup$
    – MarcoB
    May 5, 2020 at 19:15
9
$\begingroup$

Indeed, FoldList[] would be the appropriate operation here:

FoldList[{2, -1, 3, -2}.Append[#2, #1] &, 0, 
         Transpose[{{7, 1, 5, 10, 10, 2, 5, 10, 10, 6},
                    {4, 1, 4, 2, 5, 2, 2, 4, 8, 10},
                    {2, 6, 1, 4, 6, 7, 4, 1, 2, 8}}]] // Rest
   {16, -13, 35, -40, 113, -203, 426, -833, 1684, -3342}

Of course, modifying the snippet above to use fun[] in the OP is not too hard to do (spot the difference!):

FoldList[fun[Append[#2, #1]] &, 0, 
         Transpose[{{7, 1, 5, 10, 10, 2, 5, 10, 10, 6},
                    {4, 1, 4, 2, 5, 2, 2, 4, 8, 10},
                    {2, 6, 1, 4, 6, 7, 4, 1, 2, 8}}]] // Rest
$\endgroup$
2
  • $\begingroup$ Many thanks for an elegant answer. I would just like to note that my function is a toy function which will be replaced by something complicated. How would your answer change if fun had to be used "as is", i.e. without using the {2, -1, 3, -2}.Append[#2, #1] & structure? $\endgroup$
    – Titus
    May 5, 2020 at 18:59
  • 1
    $\begingroup$ See the edited version. $\endgroup$ May 6, 2020 at 0:22
3
$\begingroup$
foldList = Rest @* FoldList[fun @* Flatten @* Reverse @* List] @* Prepend[0] @* Transpose;

Example:

sp = {{7, 1, 5, 10, 10, 2, 5, 10, 10, 6}, {4, 1, 4, 2, 5, 2, 2, 4, 8, 10}, 
  {2, 6, 1, 4, 6, 7, 4, 1, 2, 8}};

foldList @ sp
{16, -13, 35, -40, 113, -203, 426, -833, 1684, -3342}

Also

foldList2 = Transpose /* Prepend[0] /* FoldList[fun @* Flatten @* Reverse @* List] /* Rest

foldList2 @ sp
 {16, -13, 35, -40, 113, -203, 426, -833, 1684, -3342}
$\endgroup$

Your Answer

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

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