3
$\begingroup$

I am looking for an elegant way to Map multiple functions over an array. My problem looks something like this:

Consider a list of functions:

f = {f1,f2,f3,f4} (* example, can be larger *)

And an array:

A = {{a1, b1, c1, d1, e1}, {a2, b2, c2, d2, e2}, {a3, b3, c3, d3, e3}}; (*example, can be larger*)

Q1: I’d like to map the functions in f over the array A so that the final result looks like:

B= {{1 - a1, f1[a1]*b1, f2[a1]*c1, f3[a1]*d1, f4[a1]*e1}, {1 - a2, 
f1[a2] b2, f2[a2] c2, f3[a2] d2, f4[a2] e2}, {1 - a3, f1[a3] b3, 
f2[a3] c3, f3[a3] d3, f4[a3] e3}}

Sample input/output

Q2: How do I map the functions a little differently so that the output looks like:

c= {{a1, f1[a1] b1, f2[b1] c1, f3[c1] d1, f4[d1] e1}, {a2, f1[a2] b2, 
f2[b2] c2, f3[c2] d2, f4[d2] e2}, {a3, f1[a3] b3, f2[b3] c3, 
f3[c3] d3, f4[d3] e3}} // tf

Alternate mapping

$\endgroup$
2
  • $\begingroup$ Just writing it out func[{a_, b_, c_, d_}] := {1 - a, b f1[a], c f2[a], d f3[a], e f4[a]} and then func/@A is pretty elegant, I think. $\endgroup$
    – C. E.
    Commented Mar 21, 2014 at 1:41
  • $\begingroup$ The issue is that the array sizes and functions I show are examples and in reality the arrays/functions are quite large so writing it out gets pretty tedious… $\endgroup$
    – Pam
    Commented Mar 21, 2014 at 1:45

2 Answers 2

5
$\begingroup$

Here's a way to write out the map concisely:

Q1:

{1 - #, ##2} Through[Join[{1 &}, f]@#] & @@@ A
(* {{1 - a1, b1 f1[a1], c1 f2[a1], d1 f3[a1], e1 f4[a1]}, 
    {1 - a2, b2 f1[a2], c2 f2[a2], d2 f3[a2], e2 f4[a2]}, 
    {1 - a3, b3 f1[a3], c3 f2[a3], d3 f3[a3], e3 f4[a3]}} *)

Q2:

Join[{1 - #[[1]]}, MapThread[#3 #@#2 &, {f, Most@#, Rest@#}]] & /@ A
(* {{1 - a1, b1 f1[a1], c1 f2[b1], d1 f3[c1], e1 f4[d1]}, 
    {1 - a2, b2 f1[a2], c2 f2[b2], d2 f3[c2], e2 f4[d2]}, 
    {1 - a3, b3 f1[a3], c3 f2[b3], d3 f3[c3], e3 f4[d3]}} *)
$\endgroup$
4
  • $\begingroup$ Holy crap… never knew there was a function called Through… this is brilliant! $\endgroup$
    – Pam
    Commented Mar 21, 2014 at 1:57
  • $\begingroup$ Any take on Q2 above? $\endgroup$
    – Pam
    Commented Mar 21, 2014 at 1:57
  • $\begingroup$ BTW, brilliant @rm-rf. $\endgroup$
    – kale
    Commented Mar 21, 2014 at 2:03
  • $\begingroup$ @Pam See edit... there probably are other ways, but this does the job. $\endgroup$
    – rm -rf
    Commented Mar 21, 2014 at 2:06
4
$\begingroup$

I was thinking about a more readable way because your question under rm's answer

Any take on Q2 above?

slightly indicates that you couldn't take it further although the idea to solve Q2 was similar. I guess my solution is in no way as easy as I had hoped it to be, but I give it anyway.

What it does is that it separates the tasks a bit. The distributor takes your list of functions and exactly one sublist like e.g. {a1, b1, c1, d1, e1} and builds up the result. For your Q1 this is just calculating 1-a1 and creating all the x1*fn[a1].

distributor[funcs_][vec_] :=
 Join[{1 - First[vec]}, #2*#1[First[vec]] & @@@ Transpose[{funcs, Rest[vec]}]
  ]

And now you can map the distributor over your A

distributor[f] /@ A

Mathematica graphics

To solve your second problem Q2 you only need to adjust the distributor which now includes a call to Partition to create sequence {{a1, b1}, {b1, c1}, {c1, d1}, {d1, e1}} we need:

distributor2[funcs_][vec_] :=
 Join[{1 - First[vec]}, #2[[2]]*#1[#2[[1]]] & @@@ Transpose[{funcs, Partition[vec, 2, 1]}]
  ]

distributor2[f] /@ A

Mathematica graphics

$\endgroup$
1
  • $\begingroup$ This is a very nice answer as well. $\endgroup$
    – Pam
    Commented Mar 21, 2014 at 2:47

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.