13

So much thanks to Szabolcs in improving sequence.. for complete explanation. I am so glad to read all explanation which fundamentally remove the problem. But in number 4 of its explanation pointed to Apply in {1} level: As we show with @@@. But I have a problem with this function. As Szabolcs pointed, this function acts as:

list = {{x1,y1}, {x2,y2}, ..., {xn,yn}}, 
 f@@@list= {f[x1,y1], f[x2,y2], ..., f[xn,yn]}

But for example we want to use Last for a list as:

m = {{1, 2, I}, {0, 0, 0}, {I, I, 3}, {2, 6, I}, {0, 0, 0}, {0, 0, 0}, {1, 6, 4}, {0, 0, 0}, {1, 4, 5}}


Last@m

{1, 4, 5}


Apply[Last, {m}]= Last@@{m}

{1, 4, 5}

Last /@ m
{I, 0, 3, I, 0, 0, 4, 0, 5}

But Apply[Last, {m}, {1}] or Last@@@{m} doesn't have any result. I predicted that I should have Last@@@ {m}={Last{1, 2, I},Last{0,0,0},....} which is the result of Last/@ m.

Also I can't understand what is the exact differnce between Last@m and Last@@{m}. I have confused with these syntax.

Unbelievable
  • 4,847
  • 1
  • 20
  • 46
  • 1
    @@@ supplies a sequence to the function being applied, with n slots where n is the length of the sublists you're mapping over. Last takes a list as an argument, so you need Last/@m, for understanding, the way to make @@@ work is to do Last[List@##]&@@@m, but that's just tearing the list apart and putting it back together. – N.J.Evans Aug 06 '15 at 15:10
  • Notice the difference in Szabolcs explanation of @@@ and f/@{{x1,y1},{x2,y2}}, which gives {f[{x1,y1}],f[{x2,y2}]} – N.J.Evans Aug 06 '15 at 15:13
  • 1
    Some possible duplicates: 78240, 46238, 70201 – shrx Aug 07 '15 at 05:26
  • 1
    Actually many operations can be phrased either in terms of Apply or Map. I should have mentioned in my answer that Map tends to be quite a bit faster than Apply. I still use Apply a lot in the exact same way I described, but for the times when performance is important, you should know that Apply tends not to be as fast as Map. – Szabolcs Aug 07 '15 at 08:56
  • 1
    To stir the pot a little, MapThread[f,{a,b}]===f@@@Transpose[{a,b}] when a and b are lists of equal length. I mentally think of MapThread as zipWith from Haskell. – Reb.Cabin Aug 07 '15 at 12:34

1 Answers1

20

I know this has been answered already on this site, but I cannot seem to find it.

Map and Apply do subtly different things. For example,

Map[f, {a,b,c}]
(* {f[a], f[b], f[c]} *)

If you have a list that is more deeply nested, without using the third argument which is for level specification, you get

Map[f, {{a,b}, {c}}]
(* {f[{a,b}], f[{c}]} *)

or, if you do use it

Map[f, {{a, b}, {c}}, 2]
(* {f[{f[a], f[b]}], f[{f[c]}]} *)
Map[f, {{a, b}, {c}}, {1,2}]
(* {f[{f[a], f[b]}], f[{f[c]}]} *)
Map[f, {{a, b}, {c}}, {2}]
(* {{f[a], f[b]}, {f[c]}} *)

But, in every case, Map applies f to each element as is.

Apply does not do that; it explicitly replaces the Head of the element with f, as follows:

Apply[f, bob[a]] (* f @@ bob[a] *)
(* f[a] *)
Apply[f, {{a, b}, {c}}, {1}] (* f @@@ {{a, b}, {c}} *)
(* {f[a, b], f[c]} *)
Apply[f, {{a, b}, {c}}, {0, 1}]
(* f[f[a, b], f[c]] *)

On the surface, these look a lot like the results from Map, but the key difference is Apply does not work on something that is AtomQ as they are effectively headless (except in special cases), e.g.

Through[{AtomQ, ValueQ}[a]]
(* {True, False} *)
f @@ a
(* a *)
f @@@ {a}
(* {a} *)

For your application, you have nested lists, and to see how those are interpreted, use FullForm, e.g.

FullForm@{{1, 2, I}, {0, 0, 0}}
(* List[List[1, 2, Complex[0, 1]], List[0, 0, 0]] *)

(As an aside, note how I is interpreted as Complex[0,1], but despite this, AtomQ@Complex[0,1] returns True.)

So, you want to use Map, e.g.

Last /@ {{1, 2, I}, {0, 0, 0}}
(* {I, 0} *)

because @@@ will replace the heads of the inner lists with Last, e.g.

f @@@ {{1, 2, I}, {0, 0, 0}} (* where f is standing in for Last *)
(* {f[1, 2, I], f[0, 0, 0]} *)
rcollyer
  • 33,976
  • 7
  • 92
  • 191
  • 2
    Since this is aimed at mid-level new users, it might be useful to point out that when Apply is used on a list of lists, List itself is a head and that {...} is just shorthand. I think people often overlook until the first time they're really confronted with it, like this. +1 – N.J.Evans Aug 06 '15 at 15:16
  • 1
    @N.J.Evans valid point. Expanded. – rcollyer Aug 06 '15 at 15:20
  • 2
    …and for the kids at home, FullForm[] will help you in playing "spot the difference". :) – J. M.'s missing motivation Aug 06 '15 at 15:21
  • 1
    @Guesswhoitis. I made a note on I being AtomQ despite its complex inner structure. – rcollyer Aug 06 '15 at 15:25
  • 3
    @rcollyer So You are AtomQ! I was looking for you! :D – Dr. belisarius Aug 06 '15 at 15:26
  • 1
    @bel, nono, Who is AtomQ… :) – J. M.'s missing motivation Aug 06 '15 at 15:51
  • 2
    @Guesswhoitis. no, he's on First. – rcollyer Aug 06 '15 at 15:55
  • @rcollyer, besides so thanks for your explanation. Imagine and understanding what you say is easy. your example using fullform helps me and my friend. FullForm[f @@@ {{1, 2, I}, {0, 0, 0}}]=List[f[1, 2, Complex[0, 1]], f[0, 0, 0]] and f can not work. But Last @@@ {{{1, 2, I}}, {{0, 0, 0}}}={I, 0}. We are so happy that we are able to understand. FullForm[f @@@ {{{1, 2, I}}, {{0, 0, 0}}}]=List[f[List[[1, 2, Complex[0, 1]]],f[List[0,0,0]]] – Unbelievable Aug 07 '15 at 03:29
  • I wonder if this is similar enough to (46238) for me to mark it as a duplicate? Obviously this answer is valuable to people and I don't wish to disparage it. But I think I covered the same material before? – Mr.Wizard Aug 07 '15 at 04:41
  • I joined two others in voting to close. I am still interested if you disagree. – Mr.Wizard Aug 07 '15 at 06:07
  • @Mr.Wizard that's one I was looking for. – rcollyer Aug 07 '15 at 10:35