8

For given functions $f,g,\cdots$ I want to define a pure function that, when applied to any list $\{x,y,\cdots\}$ (of the same length as $\{f,g,\cdots\}$), produces $\{f[x],g[y],\cdots\}$. Two ways to achieve this are

{f@#[[1]],g@#[[2]],...} &

and

MapThread[
   #1[#2] & (* or Apply[#1,{#2}] & *),
   {{f,g,...},#}
] &

With all of Mathematica's built in functions, however, I would be surprised if there does not exist a slicker way to do this. Thus my question is: is there a more elegant way to do the above?

For concreteness let's take just to functions $\{f,g\}$ and apply it to $\{x,y\}$, yet I'm hoping for an answer that generalizes to more than two functions.

Although I would expect that this has been asked here before I cannot find it.

Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263
Jules Lamers
  • 1,074
  • 9
  • 19

4 Answers4

6

Let lst1 be the list of heads of your functions:

lst1={f,g,h};

for example they may be Cos, Sin, Exp and so on, and lst2 is the list of numbers to which you want to apply the heads:

lst2={a,b,c};

A most simple way seems me to be this:

    Transpose[{lst1, lst2}] /. {x_, y_} -> x[y]

(*   {f[a], g[b], h[c]}  *)

Another way would be to first introduce a function:

   s[x_, y_] := x[y]

and with its use do this:

MapThread[s, {lst1, lst2}]

(*  {f[a], g[b], h[c]}  *)

or this:

Inner[s, lst1, lst2, List]

{f[a], g[b], h[c]}

One can probably find something else, but in the moment I do not see.

Have fun!

Alexei Boulbitch
  • 39,397
  • 2
  • 47
  • 96
2

I think the MapThread approach is already elegant. Anyway, the following is the shortest solution so far:

#@#2 & @@@ ArcTan[{f, g}, #] &
xzczd
  • 65,995
  • 9
  • 163
  • 468
  • Do you have a specific reason for using ArcTan? – Jules Lamers Nov 02 '16 at 12:54
  • 2
    @JulesLamers No, if you use List, then you only got {f[g], x[y]}. I use ArcTan because it owns Listable attribute and seems not to evaluate to other things even if its 2nd argument is some special number e.g. ArcTan[f, 0] still outputs ArcTan[f, 0]. – xzczd Nov 02 '16 at 12:56
  • (You're right, my suggestion to use List instead of ArcTan was incorrect; I edited my comment accordingly) – Jules Lamers Nov 02 '16 at 13:00
2

One can use the Listable attribute to apply a list of function to lists of arguments. One can extend it easily to multiple lists of arguments (see last example).

Either via Function:

Function[{x, y}, x[y], Listable][{f, g, h}, {x, y, z}]
(*  {f[x], g[y], h[z]}  *)

Or via a symbol:

Block[{threadApply},
 SetAttributes[threadApply, Listable];
 threadApply[f_, x___] := f[x];
 threadApply[{f, g, h}, {x, y, z}]
 ]
(*  {f[x], g[y], h[z]}  *)

With the symbolic form, it's easy to deal with an arbitrary number of arguments:

Block[{threadApply},
 SetAttributes[threadApply, Listable];
 threadApply[f_, x___] := f[x];
 threadApply[{f, g, h}, {a, b, c}, {x, y, z}]
 ]
(*  {f[a, x], g[b, y], h[c, z]}  *)

Block[{threadApply},
 SetAttributes[threadApply, Listable];
 threadApply[f_, x___] := f[x];
 threadApply[{f, g, h}]
 ]
(*  {f[], g[], h[]}  *)

This is also possible with a slight modification of the OP's original MapThread:

MapThread[#1[##2] &, {{f, g, h}, {a, b, c}, {x, y, z}}]
(*  {f[a, x], g[b, y], h[c, z]}  *)
Michael E2
  • 235,386
  • 17
  • 334
  • 747
  • Cool, thanks for your answer! It's nice to see the versions with several arguments as well. Just a small question about the final version: why do you prefer #1[##2]& over Compose? – Jules Lamers Dec 12 '16 at 12:28
  • 1
    @JulesLamers You're welcome! Note that Compose[f, a, x] and #1[##2]&[f, a, x] are not the same. There's also this warning: http://reference.wolfram.com/language/ref/Compose.html – Michael E2 Dec 12 '16 at 13:15
  • As for the first of course you're quite right, I was thinking about the two-argument case. Regarding the latter I did see that warning, but since Compose and Composition are different I'm not sure what to do with it; am I supposed not to useCompose` any more? – Jules Lamers Dec 12 '16 at 13:25
  • 1
    @JulesLamers I suppose Compose is not going away (since it hasn't after nine version updates). I'll probably use #1[#2]& or Composition with # and & depending on the case. It's not a big deal to me, but I'd rather not have my code dependent on it. Even if it were to go away, it's easy enough to add a definition. – Michael E2 Dec 12 '16 at 13:37
1

Encouraged by the comments I think that the following slight improvement, suggested by xavier (user31159), of the second attempt I included in my question is (at least quite close to) what I was hoping for:

MapThread[
  Compose,
  {{f,g,...},#}
] &

Thanks for the other suggestions as well!

Jules Lamers
  • 1,074
  • 9
  • 19