8
$\begingroup$

Is there a clean way to fold a list but alternate functions used?

Say we call such function FoldAlternating. Then for example,

The FoldAlternating[{Plus,Times}, {1, 5, 2, 3, 3, 2, 5}]] would produce 235,

Because it is equivalent to Times[Plus[Times[Plus[Times[Plus[1, 5], 2], 3], 3], 2], 5].


Edit: For $2$ functions f,g and starting value v_: 1, I can do it recursively:

fa[f_, g_, list_, v_: 1, i_: 1] := 
 If[i + 1 == Length[list], f[g[v, list[[i]]], list[[i + 1]]], 
  If[i == Length[list], g[v, list[[i]]], 
   fa[f, g, list, f[g[v, list[[i]]], list[[i + 1]]], i + 2]]]

where fa[Times, Plus, {5, 2, 3, 3, 2, 5}] gives the expected example from above.

$\endgroup$

3 Answers 3

8
$\begingroup$
ClearAll[foldRotate]
foldRotate = Module[{fl = #}, Fold[Last[fl = RotateLeft[fl]]@## &, ##2]] &;

Examples:

foldRotate[{Plus, Times}, {1, 5, 2, 3, 3, 2, 5}]
 235
foldRotate[{Plus, Times}, 1, {5, 2, 3, 3, 2, 5}]
 235
foldRotate[{foo, bar, fum}, {a, b, c, d, e}]
foo[fum[bar[foo[a, b], c], d], e]
$\endgroup$
2
  • 1
    $\begingroup$ Clever! Very nice indeed. $\endgroup$
    – MarcoB
    Commented May 4, 2020 at 3:34
  • $\begingroup$ Thank you @MarcoB. $\endgroup$
    – kglr
    Commented May 4, 2020 at 3:47
4
$\begingroup$

Maybe something like this:

ClearAll[foldAlternating];
foldAlternating[{f1_, f2_}, lst_] := Fold[
    {First@#1 + 1, Replace[First@#1, {_?OddQ :> f1, _ :> f2}]@@{Last@#1, #2}} &,
    {1, First@lst}, Rest@lst
] // Last;

foldAlternating[{Plus, Times}, {1, 5, 2, 3, 3, 2, 5}]
(* 235 *)

It would be easy enough to generalise such a function.

EDIT

In fact, here is a generalisation:

ClearAll[foldAlternating];
foldAlternating[fnsLst_, lst_] := Fold[
    {Mod[First@#1 + 1, Length[fnsLst]], (fnsLst[[First@#1 + 1]])@@{Last@#1, #2}} &,
    {0, First@lst}, Rest@lst
] // Last;

foldAlternating[{Plus, Times}, {1, 5, 2, 3, 3, 2, 5}]
(* 235 *)

foldAlternating[{Plus, Times, Mod}, {1, 5, 2, 4}]
(* 0 *)

foldAlternating[{Plus, Times, Mod}, {1, 5, 2, 3, 3, 2, 5, 7, 10, 9}]
(* 8 *)
$\endgroup$
3
$\begingroup$

How about a simple loop? (I know we are not supposed to use loops in Mathematica, but unless it is very inefficient, I do not see problem myself using loops)

foldAlternating[f_, g_, lst_] := Module[{z, n},
   z = f[lst[[1]], lst[[2]]];
   op = g;
   Do[
    z = op[z, lst[[n]]];
    op = If[op === f, g, f]
    , {n, 3, Length@lst}
    ];
   z
   ];

To use it

lst = {1, 5, 2, 3, 3, 2, 5};
foldAlternating[Plus, Times, lst]
(*235*)

Note, this assumes lst is at least 3 elements long. Easy to add error checking if needed.

ps. do not name your own functions starting with UpperCaseLetter so not to confuse them with Mathematica's own functions, unless they are inside your own package.

$\endgroup$
0

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.