15

I have a list of functions

myFuncs = {f,g,h}

which I'd like to map over an expression

expr = y[u,v,w]

to obtain y[f[u],g[v],h[w]]. Which function(s) accomplishes this task? The function is a combination of Inner and Map.

innerMap[myFuncs, expr] := (* ?? *)
QuantumDot
  • 19,601
  • 7
  • 45
  • 121

7 Answers7

13

Using Mapthread

innerMap[funcs_, expr_] := Head[expr] @@ MapThread[#1[#2] &, {funcs, List @@ expr}]
innerMap[myFuncs, expr]

y[f[u], g[v], h[w]]

NonDairyNeutrino
  • 7,810
  • 1
  • 14
  • 29
11
Inner[# @ #2 &, #, {##} & @@ #2, #2[[0]]] &[myFuncs, expr]

y[f[u], g[v], h[w]]

or

Inner[Construct, #, List @@ #2, Head @#2] &[myFuncs, expr]

y[f[u], g[v], h[w]]

Also

Construct @@@ Thread[{#2[[0]] @@ #, #2}, #2[[0]]] &[myFuncs, expr]

y[f[u], g[v], h[w]]

and

Operate[Apply[#]@*(Compose @@@ Thread @{myFuncs, {##}} &) &, expr]

y[f[u], g[v], h[w]]

kglr
  • 394,356
  • 18
  • 477
  • 896
9
MapIndexed[myFuncs[[#2[[1]]]][#] &, expr]

or

MapIndexed[Extract[myFuncs, #2][#] &, expr]

or

ReplacePart[expr, i_ :> myFuncs[[i]]@expr[[i]]]

or

expr // Query[Thread[Range@Length@myFuncs -> myFuncs]]

or

Head[expr] @@ Array[myFuncs[[#]]@expr[[#]] &, Length@expr]

or

Head[expr] @@ Construct @@@ Transpose @ {myFuncs, List @@ expr}
WReach
  • 68,832
  • 4
  • 164
  • 269
7

I'm not sure if this counts as a separate case per se, so here it goes:

threadOver[f_List, h_[x__]] := Inner[Construct, f, {x}, h]

As an example, evaluate threadOver[myFuncs, expr] to obtain:

y[f[u], g[v], h[w]]

A more complicated instance of my threadOver function making use of ListCorrelate could be the following:

threadOver[f_List, h_[x__]] := ListCorrelate[f, {x}, {1, -1}, 0, Construct, h] // First

Notes*:

The first version of threadOver (the one using Inner) seems to be, for the most part, contained in the example provided at the 'Applications' section for Construct at the Documentation Center

(happy new year!)

5

It's funny how convoluted all of these answers need to be. Here's another convoluted one. It's clunky because it does extra operations and then removes these extra pieces.

innerMap[fs_, expr_] := Through@*fs /@ expr // MapIndexed[#1[[First@#2]] &]
innerMap[{f, g, h}, y[u, v, w]]
(* y[f[u], g[v], h[w]] *)

(The function MapIndexed[#1[[First@#2]] &] was the best way I could come up with implementing Diagonal for arbitrary head expressions.)

march
  • 23,399
  • 2
  • 44
  • 100
3

If you are allowed to modify expr in place, this would do the trick:

expr[[1;;-1]] = MapThread[Construct, {myFuncs, Level[expr,1]}]
expr
y[f[u],g[v],h[w]]

Otherwise, you could use the following function:

innerMap[fs_, expr_] := Head[expr] @@ MapThread[Construct, {fs, Level[expr,1]}] 
innerMap[myFuncs, expr]
y[f[u],g[v],h[w]]
Sylvain Leroux
  • 1,509
  • 5
  • 15
3

Using an Iterator:

With[{fn = GeneralUtilities`ListIterator[{f, g, h}]},
 Unevaluated@Read[fn] /@ y[u, v, w]]

(*  y[f[u], g[v], h[w]]  *)
Michael E2
  • 235,386
  • 17
  • 334
  • 747
  • I have never seen Iterator before! It's quite old, too. – QuantumDot Jan 01 '20 at 17:42
  • @QuantumDot It can be convenient, but it hasn't got a lot of exposure. There are hints in the comments that something better might be on its way, but it's been a while. Note that for performance-intensive operations, Table, Do-loops, and Map-ping over packed arrays are much more efficient. – Michael E2 Jan 03 '20 at 17:12