# another way to do this mapping of a two argument function

Sorry, I'm just starting to learn mathematica.

I have the following two-argument function:

h[{x_, y_}] := x ^ y


When I do the following:

Map[h, {{1, 2}, {2, 2}, {3, 2}}]


I get the expected output:

{1, 4, 9}


I was wondering what I'm doing wrong with the following rewrite of the above map expression (I want to learn how to use #1 ... #n 's):

 #1 ^ #2 & /@ {{1, 2}, {2, 2}, {3, 2}}


the error messages I'm getting are:

Function::slotn: "Slot number 2 in #1^#2& cannot be filled from (#1^#2&)[{1,2}]"

Function::slotn: "Slot number 2 in #1^#2& cannot be filled from (#1^#2&)[{2,2}]."

Function::slotn: "Slot number 2 in #1^#2& cannot be filled from (#1^#2&)[{3,2}]."

-

If you want to use Map[] that is possible too:

#[[1]]^#[[2]] & /@ {{1, 2}, {2, 2}, {3, 2}}

-
thanks! I do prefer to use Map[] – john peter May 9 '13 at 23:00
@johnpeter Why? Apply is really more appropriate here, and you did explicitly say that you want to learn to use #1, #2, ..., #n, which will only be useful if you go with Apply. – Szabolcs May 9 '13 at 23:03
i'm just starting to learn. :-) I guess in this particular case, I was trying to learn how to express the same Map expression differently using #'s. Now I understand what I'm doing wrong, and all of the first 3 answers did help me! – john peter May 9 '13 at 23:27
@Artes I presume you mean worst for execution time? Given that Map[] auto compiles and @@@ doesn't I don't think the streamlined tests on the linked page you gave tell the whole story. Other than that there are conceptual concerns. You could argue for Apply there as well, but one point here is that you never move away from the data as a List by keeping it conceptually simple with Map[]. – SEngstrom May 9 '13 at 23:43
@SEngstrom If you don't believe, provide your own tests. You'll convince of that. – Artes May 9 '13 at 23:48

First of all, let's clarify that if you define h as

h[{x_, y_}] := ...


then it takes a single argument which is a list of two items. If you define it as

h[x_, y_] := ...


then it takes two separate arguments.

#n denotes the nth argument in a pure function. In the function call (#1^#2)& [{2,3}] you are passing the pure function a single argument. #2 won't have a value so you get an error. If you pass it two arguments, everything is fine: (#1^#2)& [2, 3]

Starting with a list of two items, such as {2,3}, you can use Apply to pass these two items to a function:

Apply[#1^#2 &, {2,3}]


An alternate notation for this is #1^#2 & @@ {2,3}.

You can also Apply at level 1. Check the docs details.

Apply[f, {{1,2}, {3,4}, {4,5}}, {1}]

(* ==> {f[1,2], f[3,4], f[4,5]} *)


A shorthand for the above is f @@@ {{1,2}, {3,4}, {4,5}}.

In conclusion, what you want is

#1^#2 & @@@ {{1,2}, {2,2}, {3,4}}

-
thanks for the explanation – john peter May 9 '13 at 23:04
Apply at level one needs to be explicit if you don't use @@@ notation: Apply[f, {{1, 2}, {3, 4}, {4, 5}}, {1}] – SEngstrom May 9 '13 at 23:07
@SEngstrom Thanks! That was a typo. – Szabolcs May 9 '13 at 23:15
If one wants to avoid Slot[]: Power @@@ {{1, 2}, {2, 2}, {3, 4}} (i.e. what amr did). – J. M. May 10 '13 at 2:46

For educational purposes, here's a couple other ways to do this:

Power @@@ {{1, 2}, {2, 2}, {3, 2}}


Power[Sequence @@ #] & /@ {{1, 2}, {2, 2}, {3, 2}}


Cases[{{1, 2}, {2, 2}, {3, 2}}, List[x__] :> Power[x]]


# /. List -> Power & /@ {{1, 2}, {2, 2}, {3, 2}}


Replace[{{1, 2}, {2, 2}, {3, 2}}, List -> Power, {2}, Heads -> True]


Note that this kind of head replacement is essentially what @@@ is doing, though @@@ does it specifically at level 1.

MapThread[Power, Transpose[{{1, 2}, {2, 2}, {3, 2}}]]


{bases, exponents} = Transpose[{{1, 2}, {2, 2}, {3, 2}}]
bases^exponents


{bases, exponents} = Transpose[{{1, 2}, {2, 2}, {3, 2}}]
(op[#1, #2] &)[bases, exponents]


You can make them awesome, SetAttributes method:

SetAttributes[f, Listable];
f[a_, b_] := op[a, b];

{bases, exponents} = Transpose[{{1, 2}, {2, 2}, {3, 2}}]
f[bases, exponents]


Thread method:

{bases, exponents} = Transpose[{{1, 2}, {2, 2}, {3, 2}}]


Third argument to Function method:

{bases, exponents} = Transpose[{{1, 2}, {2, 2}, {3, 2}}]
Function[{a, b}, op[a, b], Listable][bases, exponents]

-
I very much prefer the first bit. – J. M. May 10 '13 at 2:47

You should use Apply (at the level 1 (@@@)) rather than Map, in terms of a pure function as you looking for:

#1^#2 & @@@ {{1, 2}, {2, 2}, {3, 2}}

{1, 4, 9}


Instead of a pure function #1^#2 & one can simply write built-in Power. Your h function takes only one argument i.e. a two-element list, while the second one (a pure function) has two arguments, so that's why you need Apply instead of Map.

There is another way which sometimes appears even faster (not for Power but for Times and Plus)

#1^#2 & @@ # & /@ {{1, 2}, {2, 2}, {3, 2}}


Similarly here one can use Power instead of #1^#2 &. Take a look at a related question on stackoverflow How to remove the extra {} when Mapping a function to a list. One of the answers contains interesting benchmarks for the both methods and you can learn there that the canonical approach @@@ is roughly 3 times faster for Power, while for Times and Plus the second one is ~4 times faster ( due to autocompilation of Map etc.).

-
thank you for the explanation – john peter May 9 '13 at 23:00
That looks like a bit of cursing before the data comes around :) – SEngstrom May 9 '13 at 23:12
thanks for the link! – john peter May 9 '13 at 23:31
@johnpeter also keep in mind that all the operators in mathematica have a FullForm representation (even operators you might not expect would have such a thing), and that you can just do, for example, Power @@@ {{1, 2}, {2, 2}, {3, 2}}. Try FullForm[HoldForm[out = #1^#2 & @@@ {{1, 2}, {2, 2}, {3, 2}}]] to see what I'm talking about. – amr May 9 '13 at 23:34

Since V10 Apply has got Operator form, so the following use is also valid:

Apply[#1^#2 &] /@ {{1, 2}, {2, 2}, {3, 2}}


{1, 4, 9}

-