7

Is there a more concise way of achieving the following result (possibly without d |->)?

(d |-> (d@Exponent[#, Variables[expr]] &)) /@ {f1, f2}

{f1[Exponent[#1, Variables[expr]]] &, 
 f2[Exponent[#1, Variables[expr]]] &}

I tried to use Through but this gives me incorrect result - the & is in the wrong place in the output.

Through[{f1, f2}[Exponent[#, Variables[expr]] &]]

{f1[Exponent[#1, Variables[expr]] &], 
 f2[Exponent[#1, Variables[expr]] &]}
azerbajdzan
  • 15,863
  • 1
  • 16
  • 48

6 Answers6

5

You can use Composition.

Longhand

Composition[#, Exponent[#, Variables[expr]] &] & /@ {f1, f2}

Shorthand

#@*(Exponent[#, Variables[expr]] &) & /@ {f1, f2}

Both give

{f1@*(Exponent[#1, Variables[expr]] &), 
 f2@*(Exponent[#1, Variables[expr]] &)}

Hope this helps.

Edmund
  • 42,267
  • 3
  • 51
  • 143
  • Yes, this is the only code in this thread that is shorter than mine. Although the output is not exactly the same it is equivalent to the requested from. – azerbajdzan Mar 11 '24 at 10:34
  • 1
    +1. It may not matter for the present context, but note that there are subtle evaluation differences between the two forms which might be important when working with symbolic expressions. e.g. ((d |-> (d[g[#]] &))@Hold)[x] vs (#@*(g[#] &) & @ Hold)[x]. – WReach Mar 11 '24 at 14:20
4
Table[{Exponent[#, Variables[expr]]} & /. List -> f, {f, {f1, f2}}]

(* {f1[Exponent[#1, Variables[expr]]] &, 
 f2[Exponent[#1, Variables[expr]]] &} *)

MarcoB
  • 67,153
  • 18
  • 91
  • 189
MelaGo
  • 8,586
  • 1
  • 11
  • 24
  • 1
    No need for the ReplaceAll indirection. Just do Table[f@Exponent[#, Variables[expr]] &, {f, {f1, f2}}] – lericr Mar 10 '24 at 19:49
  • 3
    @lericr: Wrong result. Who could upvote a comment without even checking it provides a correct result? – azerbajdzan Mar 10 '24 at 20:06
  • 2
    @lericr That results in {f[Exponent[#1, Variables[expr]]] &, f[Exponent[#1, Variables[expr]]] &} - I don't fully understand why it doesn't work though. – MelaGo Mar 10 '24 at 20:17
  • Yep, my bad. That always happens when I try to reply without having MMA in front of me. It's the HoldAll attribute that causes the problem, I think. – lericr Mar 10 '24 at 22:19
  • @lericr Seems right, since this also works: ReleaseHold@ Table[Evaluate@f@Hold@Exponent[#, Variables[expr]] &, {f, {f1, f2}}] – MelaGo Mar 10 '24 at 22:31
4

If you literally just want shorter, you can just use a different version of Function:

#@Exponent[#, Variables[expr]] & & /@ {f1, f2}
lericr
  • 27,668
  • 1
  • 18
  • 64
  • Again, the & is not at the position as requested. It is easy to overlook. ]] &] instead of ]] ]&. – azerbajdzan Mar 11 '24 at 10:18
  • dang it. I've updated. I thought the parens would make no difference so added for clarity, and then just visually overlooked the discrepancy. – lericr Mar 11 '24 at 15:17
  • Actually, it does work with parens if you do it this way: (#@Exponent[#, Variables[expr]] &) & /@ {f1, f2}. It's early and maybe I need more coffee, but I'm not really sure why this way works but my original doesn't. – lericr Mar 11 '24 at 15:21
  • Yes, now it is correct. – azerbajdzan Mar 11 '24 at 15:25
  • Oh, I'm an idiot. I see what was wrong with the parens now. Not sure what I was thinking. – lericr Mar 11 '24 at 15:31
3

A dirty alternative:

ComapApplyPureFunction[funcs_?VectorQ, pf_Function] := Module[{strpf},
strpf = StringDelete[ToString[pf], "&"];
ToExpression[#1 <> #2 & @@@ 
Thread[{ToString@#2@#1 & @@@ Thread[{strpf, ToString /@ funcs}], 
Array["&" &, Length@funcs]}]]]

Testing ComapApplyPureFunction:

ComapApplyPureFunction[{f1, f2}, Exponent[#, Variables[expr]] &]

({f1[Exponent[#1, Variables[expr]]] &, f2[Exponent[#1, Variables[expr]]] &})

Addendum:

Perhaps using Function instead of an anonymous function will allow you to implement what you are looking for in a more concise way. The following example can be useful:

expr = x^2 + 2  x + 1;

With[{f1 = #^2 &, f2 = #^3 &}, ReleaseHold@#2@#1 & @@@ Thread[{HoldForm[Function[x, Exponent[x, Variables[x]]]@expr], {f1, f2}}]]

({{4}, {8}})

E. Chan-López
  • 23,117
  • 3
  • 21
  • 44
3

I think that in Version 14, you would be able to write

fn = Comap[{f1, f2}]@*(Exponent[#, Variables[expr]] &)

With this definition, you would the have

expr = a + b + c
(* a + b + c *)

fn[expr] (* Comap[{f1, f2}][{1, 1, 1}] *)

which I think would be what you wanted (if Comap were defined).

I haven't tested this, as I haven't installed version 14 yet.

mikado
  • 16,741
  • 2
  • 20
  • 54
2

Although not more concise, it might be worth noting (as pointed out by Wagner, p196) that a pure function may be made listable using Function[] syntax (but not, as far as I am aware, with either #-& or d |-> syntax).

{f1, f2} // Function[x, x[Exponent[#, Variables[expr]]] &, Listable]

(* {f1[Exponent[#1, Variables[expr]]] &, f2[Exponent[#1, Variables[expr]]] &} *)

The following will also work:

myfn = Function[x, (x[Exponent[#, Variables[expr]]] &), Listable];

myfn[{f1, f2}]

(* {f1[Exponent[#1, Variables[expr]]] &, f2[Exponent[#1, Variables[expr]]] &} *)

But (as again pointed out by Wagner), the following won't, as the listable attribute is 'stripped off' when fn is replaced by its ownvalue during evaluation:

fn = Function[x, (x[Exponent[#, Variables[expr]]] &)];
SetAttributes[fn, Listable]
fn[{f1, f2}]

(* {f1, f2}[Exponent[#1, Variables[expr]]] & *)

user1066
  • 17,923
  • 3
  • 31
  • 49