3

What's the correct way to form a table of buttons in which each action depends on the index in the table? E.g., I want to get

{Button[1,f[1]],Button[2,f[2]]}

but the obvious attempt

Table[Button[i,f[i]],{i,1,2}]

fails because the second argument of Button is held.

What's the idiomatic way to do this?

2 Answers2

4

You can use With

Table[With[{i = i}, Button[i, f[i]]], {i, 1, 2}]
Karsten7
  • 27,448
  • 5
  • 73
  • 134
  • Thanks. I don't think I would soon have hit upon that: reminding the interpreter that i=i doesn't seem like it would all that helpful. I'm beginning to think that Mathematica isn't such a great language. – Andrew Dabrowski Feb 03 '16 at 01:51
  • @AndrewDabrowski It's a well documented behavior. See http://wolfram.com/xid/0mrh4y-qke and http://wolfram.com/xid/0gisaa-y9z for example. Also, this isn't really an issue of "reminding the interpreter that i=i", it's more about scoping. Table is effectively using Block and the Button action is only evaluated, when the Button is clicked. – Karsten7 Feb 03 '16 at 03:20
  • 2
    The key point to remember is that With can inject to held expressions. And Button is HoldRest. p.s. i=i is arbitrary, it can be whatever = i and now you have to put whatever to the button, with i=i you don't have to change the code, that's why it is often used. – Kuba Feb 03 '16 at 06:50
  • Thanks for your help. I still think these fussy scoping rules are a negative for the language. It seems Wolfram is still paying for mistakes he made 25 years ago. Wouldn't the natural way to specify a handler be as a function, perhaps with a HandlerArguments option? Using a held expression seems to me a terrible idea. Maybe I should just write an alternative... – Andrew Dabrowski Feb 03 '16 at 18:40
2

This too does the same thing:

Button[#, f[#]] & /@ Range@2

Also an ugly but stupid way:

Table["Button[" <> ToString@i <> ",f[" <> ToString@i <> "]]", {i, 2}] // ToExpression

One can write it down without thinking.

stark
  • 103
  • 3
whxhsn
  • 96
  • 7