5

I want simple syntax that results in this:

{{f[1, 2], g[1, 2]}, {f[3, 4], g[3, 4]}}

though I'm willing to settle for:

{{f[{1, 2}], g[{1, 2}]}, {f[{3, 4}], g[{3, 4}]}}

if that's easier somehow. (And for completeness, and Re: the answer I accepted, I'm also fine with the form

{{f[1, 2], f[3, 4]}, {g[1, 2], g[3, 4]}}

which differs from the original form by a simple Transpose anyway.)

I would expect the function Through to help here, but it doesn't seem able to work with functions that take multiple arguments. My naive attempt looks like this:

Through@{f, g}[{{1, 2}, {3, 4}}]

{f[{{1, 2}, {3, 4}}], g[{{1, 2}, {3, 4}}]} (*out*)

which is clearly not what I want (as it does no threading over the arguments). If a function is defined to take one argument, then Through makes the most of that:

f[x_] := x^2
g[x_] := x^3
Through@{f, g}[{{1, 2}, {3, 4}}]

{{{1, 4}, {9, 16}}, {{1, 8}, {27, 64}}} (*out*)

(f and g now get applied to the lowest level, where there's only 1 argument.) So what I want is a way to get Through to 'make the most' of functions that take multiple arguments. Instead it gives me:

Clear[f, g]
f[x_, y_] := x^2 + y
g[x_, y_] := x^3 + y
Through@{f, g}[{{1, 2}, {3, 4}}]

{f[{{1, 2}, {3, 4}}], g[{{1, 2}, {3, 4}}]} (*out*)
Max
  • 1,050
  • 6
  • 14

6 Answers6

8

I like using Slot free notation, so the following appeals to me:

Through @* {f, g} @@@ {{1, 2}, {3, 4}}

{{f[1, 2], g[1, 2]}, {f[3, 4], g[3, 4]}}

And for the OP using version 9:

Through /@ {f, g} @@@ {{1, 2}, {3, 4}}

{{f[1, 2], g[1, 2]}, {f[3, 4], g[3, 4]}}

Also, the short hand @* was introduced in M10, but you can still use the long hand in earlier versions:

Composition[Through, {f, g}] @@@ {{1, 2}, {3, 4}}

{{f[1, 2], g[1, 2]}, {f[3, 4], g[3, 4]}}

Carl Woll
  • 130,679
  • 6
  • 243
  • 355
4
list = {{1, 2}, {3, 4}};

Apply[#, list, {1}] & /@ {f, g}

{{3, 13}, {3, 31}}

Or with the operator form of Map:

Map[Apply[#, list, {1}] &] @ {f, g}

Or in terse notation:

# @@@ list & /@ {f, g}
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
eldo
  • 67,911
  • 5
  • 60
  • 168
  • Though several people gave good answers, I like yours best for both simplicity and that it gives the (slightly) preferred output that I mentioned at the beginning of my post. – Max Aug 28 '17 at 22:18
  • 2
    @Max This does not produce the form you requested, {{f, f}, {g, g}} rather than {{f, g}, {f, g}}. – Mr.Wizard Aug 29 '17 at 10:28
  • 2
    @Mr.Wizard You're right. But it so happens that difference isn't important to me (and besides it's a simple Transpose away) -- I'll edit my question to reflect that. And for future readers, I imagine this answer could still be the most convenient because it works with the standard function form f[x,y], rather than needing a re-definition f[{x_,y_}]:=f[x,y] as the other answers do. – Max Aug 29 '17 at 16:57
  • Though @Carl Woll gave a modification to J.M.'s comment that makes it usable with the standard f[x,y] form as well. – Max Aug 29 '17 at 17:41
  • @Max, right, Carl is using level-1 Apply[] (@@@) in his instead of Map[] (/@) in mine, which did expect lists as arguments. – J. M.'s missing motivation Aug 29 '17 at 23:46
3
func[x_List] :=  Module[{},
  Map[Through[{f, g}[#] ] &, x]
]
user42582
  • 4,195
  • 1
  • 10
  • 31
Alucard
  • 2,639
  • 13
  • 22
2

Using Comap: (since v14.0, 2023)

Comap[{f,g},#]&/@{{1, 2}, {3, 4}}

{{f[{1,2}],g[{1,2}]},{f[{3,4}],g[{3,4}]}}


Using ComapApply: (since v14.0, 2023)

ComapApply[{f,g},#]&/@{{1, 2}, {3, 4}}

{{f[1,2],g[1,2]},{f[3,4],g[3,4]}}

Syed
  • 52,495
  • 4
  • 30
  • 85
2

Using Query

Query[All, {f, g}] @ {{1, 2}, {3, 4}}

{{f[{1, 2}], g[{1, 2}]}, {f[{3, 4}], g[{3, 4}]}}

eldo
  • 67,911
  • 5
  • 60
  • 168
2

Using Tuples and SplitBy:

Thread@SplitBy[#1 @@ #2 & @@@ Tuples[{{f, g}, {{1, 2}, {3, 4}}}], Head]

{{f[1, 2], g[1, 2]}, {f[3, 4], g[3, 4]}}

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