15
$\begingroup$

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] := (* ?? *)
$\endgroup$

7 Answers 7

9
$\begingroup$
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}
$\endgroup$
13
$\begingroup$

Using Mapthread

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

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

$\endgroup$
1
  • 1
    $\begingroup$ Instead of #1[#2]& you can also use Construct (introduced in 11.3) $\endgroup$
    – Gerli
    Commented Dec 31, 2019 at 8:50
11
$\begingroup$
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]]

$\endgroup$
7
$\begingroup$

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!)

$\endgroup$
5
$\begingroup$

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.)

$\endgroup$
3
$\begingroup$

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]]
$\endgroup$
3
$\begingroup$

Using an Iterator:

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

(*  y[f[u], g[v], h[w]]  *)
$\endgroup$
2
  • $\begingroup$ I have never seen Iterator before! It's quite old, too. $\endgroup$
    – QuantumDot
    Commented Jan 1, 2020 at 17:42
  • $\begingroup$ @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. $\endgroup$
    – Michael E2
    Commented Jan 3, 2020 at 17:12

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.