5

This returns errors:

{#[[1]],#[[3]]} & /@ {#[[1]],#[[2]],#[[3]]} & /@ {{"A","B","C"},{1,2,3}}

Part::partd: Part specification A[[1]] is longer than depth of object. >>
...

But when adding parentheses after first /@ (Map) and closing it on the end of expression, as in:

{#[[1]],#[[3]]} & /@ ({#[[1]],#[[2]],#[[3]]} & /@ {{"A","B","C"},{1,2,3}})

everything goes fine and returns expected result: {{"A", "C"}, {1, 3}}

How to explain the behavior of first case? I cannot figure out what cause errors in first case.

Michael E2
  • 235,386
  • 17
  • 334
  • 747
Dragutin
  • 920
  • 5
  • 14
  • 1
    Your question notwithstanding, are you perhaps looking for {{"A", "B", "C"}, {1, 2, 3}}[[All, {1, 3}]]? You might also be interested in Elegant operations on matrix rows and columns. – MarcoB Jul 05 '16 at 18:57
  • No. I ask, why first case returns errors: "Part specification \!\(\"A\"[[1]]\) is longer than depth of object.", and returns something like generic result {{{"A"[[1]], "A"[[3]]}, {"B"[[1]], "B"[[3]]}, {"C"[[1]], "C"[[3]]}}, {{1[[1]], 1[[3]]}, {2[[1]], 2[[3]]}, {3[[1]], 3[[3]]}}} Expected result should be as in 2nd case. – Dragutin Jul 05 '16 at 19:01
  • 3
    Perhaps you could point out explicitly why you think that the behavior you observed is not in accordance with operator precedence rules (see e.g. Operator Input Forms and [this answer]).(http://mathematica.stackexchange.com/a/30430/27951). – MarcoB Jul 05 '16 at 19:25
  • Tank you. I figured out the point I missed. This was the the way the Map function works on it's arguments. – Dragutin Jul 05 '16 at 22:12

2 Answers2

6

To understand grouping and precedence, use HoldForm and PrecedenceForm. I'll insert a screenshot to make the output clearer:

enter image description here

It is useful to know that // has even lower precedence than & and can save you some parentheses.

You probably meant:

({#[[1]], #[[3]]} &) /@ ({#[[1]], #[[2]], #[[3]]} &) /@ {{"A", "B", "C"}, {1, 2, 3}}

It is useful to parenthesize the entire function because & has very low precedence, lower than most other operators. Thus it tends to act on everything preceding it.


Another common mistake with & is using it like this in options:

SomeFunction -> #&

This is really (SomeFunction -> #)& and not SomeFunction -> (#&).


One of the few operators that have even lower precedence than & is //. Thus this is safe:

argument // #&

It groups as argument // (#&) and not as (argument // #)&.


Alternative ways to write you expression are:

Map[{#[[1]], #[[3]]} &] @ Map[{#[[1]], #[[2]], #[[3]]} &] @ {{"A", "B", "C"}, {1, 2, 3}}

{{"A", "B", "C"}, {1, 2, 3}} // Map[{#[[1]], #[[2]], #[[3]]} &] // Map[{#[[1]], #[[3]]} &]

You may or may not find these more readable than the explicitly parenthesized version.

Recently I prefer the latter when doing a lot of chaining.

Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263
2

Perhaps this example helps:

3 # & /@ Sin[#] & /@ {x, y, z}
(*{Sin[3 x], Sin[3 y], Sin[3 z]}*)

vs.

3 # & /@ (Sin[#] & /@ {x, y, z})
(*{3 Sin[x], 3 Sin[y], 3 Sin[z]}*)
yarchik
  • 18,202
  • 2
  • 28
  • 66
  • OK. this is useful as a starting point for me. But: Trace[3#& /@ Sin[#] &@x] produces {((3#1&)/@Sin[#1]&)[x], (3#1&), /@ Sin[x], Sin[(3#1&)[x]], {(3#1&)[x], 3x}Sin[3x]}. And I don't understan how 3rd step isproduced, because Map[f, expr] is equvalent of f /@ expr, so 3rd step should be 3 [Sin[x]]. Where is the point I miss? – Dragutin Jul 05 '16 at 20:36
  • @Dragutin Doesn't PrecedenceForm make it clear what is happening? – Szabolcs Jul 06 '16 at 08:05
  • Yes. Tank you. Now everything is clear. I missunderstood functioning of Map function. – Dragutin Jul 06 '16 at 08:35