27

I want to use a list of tuples within a function to make assignments.

Say I want to make assignments of the form

value[i,j] = val

What I have is a list of tuples that give the relevant indices (i,j):

tuples = {{i[1],j[1]},{i[1],j[2]}, ... , {i[imax],j[jmax]}}

What I have found is that this statement will work in Mathematica 8 :

Function[t, value[t[[1]], t[[2]]] = 0.] /@ tuples

But using slots does somehow not work:

value[#[[1]],#[[2]]] = 0. & /@ tuples

... gives an error.

Where is the mistake I am making or is there no way to do this using slots? (using Part[#,1] and Part[#,2] will not help either]?

gwr
  • 13,452
  • 2
  • 47
  • 78

2 Answers2

55

It is good practice to check the precedence of code that is not behaving as you expect.

  • One of the easiest ways to do this is to use Ctrl+. to expand the selection outward from the cursor while respecting Mathematica precedence.

  • Converting the expression to StandardForm (Ctrl+Shift+N) will often reveal something about the way Mathematica is parsing your code.

  • Explicitly parenthesize the code using group, supplied below.

  • Wrapping the code with HoldForm[FullForm[ . . . ]] (or appending // FullForm // HoldForm) is a robust but harder to read way to check exactly what Mathematica makes of your code.

  • In this case syntax highlighting should also tell you that something may be wrong, but the highlighting is not entirely reliable. (It may show errors on some correct code.)

  • As a last resort if other methods fail e.g. because your code has syntax errors you can use UndocumentedTestFEParserPacket to see how the Front End is parsing it. Example:

In the image below I have converted to StandardForm and also used Ctrl+. to expand the selection. You can see that Mathematica is parsing your Function as (0. &) and that the Map operation is being done before the Set operation.

Mathematica graphics

A function to explicitly parenthesize code:

SetAttributes[group, HoldFirst]

group[expr_] := 
  Replace[
    Unevaluated[expr], 
    x : _[___] :>
      RawBoxes @ RowBox[{"(", ToBoxes @ Unevaluated @ x, ")"}],
    {0, -1}
  ];

Applied to your case:

group[
  value[#[[1]], #[[2]]] = 0. & /@ tuples
]
((value[((#1)[[1]]), ((#1)[[2]])]) = ((0. &) /@ tuples))
  • This may be easier to read than the FullForm as it tends to expand code less.
  • The output of group is valid input which may be used as-is or modified.
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • 1
    I am going to use ctrl-. more! I didn't know it's precedence-aware'that's quite useful. I mostly use ctrl-shift-B to extend my selection and check the balance at the same time. – Sjoerd C. de Vries Mar 18 '12 at 20:50
  • @gwr Thanking anyone who answered is nice, but don't feel it as a being a requirement: http://meta.stackexchange.com/questions/17878/thanking-users-who-answered-my-question – Sjoerd C. de Vries Mar 18 '12 at 20:57
23

This is a precedence issue: You may use

(value[#[[1]], #[[2]]] = 0.) & /@ tuples

instead (ie, explicitly indicate precedence by using brackets).

One way to see what is going on is to notice the colour of the # in the notebook. Or select the & symbol, then press Ctrl+. repeatedly. This progressively selects larger chunks of the expression to which the currently selected expression belongs, and does so in order of precedence. You then will see that 0. & /@ tuples is what mma sees.

You can also use

Trace[value[#[[1]], #[[2]]] = 0. & /@ tuples]

and notice that at some point mma tries to evaluate

value[#1[[1]], #1[[2]]] = {0., 0., 0.}

which is what gives the error (and is due to the precedence issue described above, as it is the result of 0.&/@tuples; tuples is set to a list of three pairs in my case).

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
acl
  • 19,834
  • 3
  • 66
  • 91
  • I am on the wrong side of this today. I didn't know you were going to expand your answer. – Mr.Wizard Mar 18 '12 at 12:27
  • @Mr.Wizard Thank you for discreetly telling me off :) But, in all seriousness, I simply did not think of saying anything other than "add brackets" in the beginning, and then changed my mind. It also annoys me when this happens to me. – acl Mar 18 '12 at 12:33
  • I am not telling you off! I am instead amused by the fact that something I supported (which I try not to do as often now) surprised me. I started to make my post an edit to yours, but as it grew longer I decided to post it separately. – Mr.Wizard Mar 18 '12 at 12:37