3
$\begingroup$

I am trying to do the following:

c[n_, x_, y_] := ToExpression["p" <> ToString[n]] = {x, y}

That is: Evaluating c[1,1,1], yields the assignment p1={1,1} but this is giving me the following error:

Set::write: Tag ToExpression in ToExpression[p2] is Protected.

I have also tried:

c[n_, x_, y_] := Evaluate[ToExpression["p" <> ToString[n]] = {x, y}]

But it also doesn't work. How can I make this work?

$\endgroup$
5
  • 1
    $\begingroup$ Set has an attribute HoldFirst, which means you have to manually evaluate the expression to get the symbol: c[n_, x_, y_] := Set[Evaluate@Symbol["p" <> ToString[n]], {x, y}] $\endgroup$
    – Domen
    Dec 4 '21 at 13:09
  • 1
    $\begingroup$ See mathematica.stackexchange.com/questions/783/… $\endgroup$
    – Alex97
    Dec 4 '21 at 13:12
  • 6
    $\begingroup$ This sounds like it might be an XY problem. For example, would c[n_,x_,y_]:=p[n]={x,y} work for your purposes? $\endgroup$
    – evanb
    Dec 4 '21 at 13:34
  • $\begingroup$ @evanb This works perfectly! Thanks! I wasn't aware I could do that. $\endgroup$
    – Red Banana
    Dec 4 '21 at 14:09
  • 1
    $\begingroup$ Great! Glad to help! $\endgroup$
    – evanb
    Dec 4 '21 at 19:42
6
$\begingroup$

I recommend that the construct ToExpression["p" <> ToString[n]] for variable names be avoided. It makes the resulting variable names more difficult to work with. It is much more flexible to use indexed variables. You can Format the display of indexed variables in any desired manner.

ClearAll[c, p]

Format[p[n_]] := "p" <> ToString[n] (* or Subscript[p,n] *)

c[n_, x_, y_] := p[n] = {x, y}

c[#, x, y] & /@ Range[5];

The five p variables have been Set

p /@ Range[7]

(* {{x, y}, {x, y}, {x, y}, {x, y}, {x, y}, "p6", "p7"} *)

Although displayed as p6 and p7, they are stored as indexed variables

% // InputForm

(* {{x, y}, {x, y}, {x, y}, {x, y}, {x, y}, p[6], p[7]} *)

As indexed variables you can more readily work with a large number of them.

SeedRandom[1234];

Total[c[#, RandomInteger[100], RandomInteger[100]] & /@ Range[20]] === 
 Total[p /@ Range[20]]

(* True *)

p[2]

(* {32, 56} *)

c[2, 6, 7] (* or p[2] = {6, 7} *)

(* {6, 7} *)

p[2]

(* {6, 7} *)
$\endgroup$
5
$\begingroup$

Look at:

Attributes[Set]
{HoldFirst, Protected, SequenceHold}

The attribute "HoldFirst" prohibits the evaluation of "Symbol[..]" as you can see from:

Symbol["p1"] = 1

Therefore, you must force the evaluation of "Symbol" by:

Clear["p*", c]
c[n_, x_, y_] := (Evaluate[Symbol["p" <>ToString[n]]]) = {x, y}
c[1, 1, 1];
p1
(* {1, 1} *)
$\endgroup$
1
  • 3
    $\begingroup$ Actually this only works first time. Try calling c[1, 1, 1] from new cell again and you will get an error Set::setraw: Cannot assign to raw object 1. $\endgroup$
    – Nasser
    Dec 4 '21 at 13:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.