4
$\begingroup$

Consider a pair of functions f1 and f2, and a vector {x,y}. I can get easily {f1[x],f2[y]} by doing MapThread[#1@#2 &,{f1,f2},{x,y}].

Now imagine that I have a function F defined as

F := {f1[#],f2[#]} &

Of course I cannot use the same procedure to get the same result, because now F is not a list of functions (as it was {f1,f2}), but a function itself that returns a list.

One way to get this result (and that admits generalization to longer lists) is

Diagonal[F/@{x,y}]

With this solution we build a whole matrix of elements of F acting on elements of the arguments list and we select the ones that we want.

I was wondering if there is a solution kind of like MapThread that gives the direct result, making act one-to-one the $n$-th element of the function with the $n$-th argument.

$\endgroup$
5
  • 3
    $\begingroup$ Using := for F is strange here. Are you aware of the distinction between Set and SetDelayed? $\endgroup$
    – Szabolcs
    Nov 25, 2016 at 11:50
  • $\begingroup$ I am. f1 and f2 are supposed to stand for concrete functions in this case (for example, F := {D[#,x],D[#,y]}&). $\endgroup$
    – dpravos
    Nov 25, 2016 at 11:56
  • 3
    $\begingroup$ := is never needed if the right-hand side only has a Function (i.e. ...&). That's because Function already holds its arguments. It doesn't hurt to use := but the result will be exactly the same as it would have been with =. $\endgroup$
    – Szabolcs
    Nov 25, 2016 at 12:19
  • $\begingroup$ Thanks, I had never thought about it. Is any of them recommended? $\endgroup$
    – dpravos
    Nov 25, 2016 at 15:20
  • 1
    $\begingroup$ I use = for OwnValue assignments unless there is a special reason not to. If I see :=, I automatically look for a special reason. This is of course just my way of working. I can't think of a technical reason why := is bad here. $\endgroup$
    – Szabolcs
    Nov 25, 2016 at 15:35

2 Answers 2

4
$\begingroup$

For f = {f1[#], f2[#], f3[#]} &; you can also turn f into a list of functions using

Function/@f[[1]] 

or using

First@MapAt[Function, f, {1, All}] (* thanks : Szabolcs *)
Thread[f] (* thanks: WReach *)

and then MapThread the resulting function list with the argument list:

ClearAll[mthreadF]
mthreadF = MapThread[#@#2 &, {Thread@#, #2}] &;

mthreadF[f, {x, y, z}]

{f1[x], f2[y], f3[z]}

Alternatively, you can use Inner:

ClearAll[innerF]
innerF = Inner[#@#2 &, Thread@#, #2, List] &;

innerF[f, {x, y, z}]

{f1[x], f2[y], f3[z]}

$\endgroup$
5
  • 1
    $\begingroup$ The difficulty is evaluation control. The OP said that he actually has things such as {D[#,x],D[#,y]}&. Dealing with this, plus dealing with the various allowed syntaxes for Function makes this complicated. That is why I said that "There isn't a reasonable way ...". But looking at your post maybe it isn't quite as unreasonable ... How about First@MapAt[Function, f, {1, All}] for simple slot-based functions like what you considered? $\endgroup$
    – Szabolcs
    Nov 25, 2016 at 13:11
  • $\begingroup$ @Szabolcs, thank you. First@MapAt[Function, f, {1, All}] is clever. I will update with your suggestion. $\endgroup$
    – kglr
    Nov 25, 2016 at 13:15
  • $\begingroup$ I think that this is the answer I was looking for. The key resides in transforming the function f that returns a list of functions in the list of functions, solved with the MapAt. I found it quite elegant. $\endgroup$
    – dpravos
    Nov 25, 2016 at 15:46
  • $\begingroup$ If we are allowed to assume that f is precisely of the form {...}&, then Thread[f] will perform the required conversion and thus mthreadF = MapThread[#@#2 &, {Thread[#], #2}] &;. $\endgroup$
    – WReach
    Nov 25, 2016 at 17:09
  • 1
    $\begingroup$ @WReach, thank you ! I added your suggestion to the answer. $\endgroup$
    – kglr
    Nov 26, 2016 at 1:31
3
$\begingroup$

There isn't a reasonable way to avoid computing both f1 and f2 in this case. But we can avoid storing the whole matrix, which would (temporarily) take up a lot of memory. One way is MapIndexed.

f = {f1[#], f2[#]} &;

MapIndexed[Extract[f[#1], #2] &, {x, y}]
(* {f1[x], f2[y]} *)

Unless the lists are large enough that the matrix would take up a lot of memory, it's probably not worth bothering with this. I would choose your solution with Diagonal because I find it clearer than MapIndexed. This is, of course, just my personal preference.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.