# Reassign values to symbols

I've got a situation where I have, say 4 symbols, a, b, c and d. This is a simplification of the issue I've been working with. Let's say I assign numeric values to these symbols:a=1; b=2; c=3; d=4. I now create a list: myList:={a,b,c,d}. I'd like to be able to say: ( # = 5 ) & /@ myList to assign the value 5 to a, b, c and d. The code works as long as a-d are unassigned. Is there a way to do this, or am I trying to abuse the language?

-
What exactly is your aim in general? (To understand your example, look at the output of Trace[myList:={a,b,c,d}] and of Trace[myList={a,b,c,d}]. The former is a mistake while the latter attempts to issue a sequence of Set assignments 1=5, 2=5, ..., 4=5.) – whuber Jan 19 '12 at 15:01
FYI: It's a bit better to use Scan[] instead of Map[] (that is, /@) for multiple assignments. – J. M. Jan 19 '12 at 15:01
A primary aim of mine is to be able to make a bunch of reassignments using map, rather than writing all of the assignment statements. Another aim is to use meaningful names for the symbols and then being able to retrieve the name of the symbol, along with any values I assign to it. Typically the symbols will represent lists, I just used integers to make it easier to write out an example. – Mitchell Kaplan Jan 22 '12 at 22:34

You could use

myList = Hold[a,b,c,d]

Function[x, x=5, {HoldAll}] /@ myList // ReleaseHold

-

This seems to work:

a = 1; b = 2; c = 3; d = 4;
Scan[Function[p, p = 5, HoldAll], Hold[a, b, c, d]]


Now, try evaluating {a, b, c, d}.

Here's the version with slots:

    Scan[Function[Null, # = 5, HoldAll], Hold[a, b, c, d]]

-
+1, Though it's very logical, I didn't realize Scan can be used in such a way on held expressions. This is an important difference between Scan and Map, that your answer highlights. – Szabolcs Jan 19 '12 at 15:23
@Szabolcs I second that. Did not realize it either. – Leonid Shifrin Jan 19 '12 at 15:59
@J.M +1 out of curiosity how did you figure out this behaviour. I've just had a scan (pun intended) of the documentation and I don't think you would know that this would work for this example from the description there. – Mike Honeychurch Jan 19 '12 at 23:07
@MikeHoneychurch Now that I see that it works, it seems very logical: Map modifies the expression, Scan takes parts of the expression and runs f[part] for each. Is our way of thinking too constrained maybe? This is why I love this site and interaction with others :-) You always learn something new – Szabolcs Jan 20 '12 at 11:56
+1, a slightly shorter variant: Scan[Function[p, p = 5, HoldAll], Hold[a, b, c, d]] – WReach Jan 21 '12 at 19:26

If you insist on working with your list where you assemble variables, this will do it:

setValues  =
Function[{vlist, val},
OwnValues[vlist] /. (_ :> vars_) :>
Replace[Unevaluated@vars, var_ :> (var = val), {1}],
HoldFirst];


For example:

In[73]:= myList:={a,b,c,d}
In[74]:= a=1;b=2;c=3;d=4;

In[77]:= setValues[myList,5];

In[78]:= myList
Out[78]= {5,5,5,5}

-
Very cool, I was writing up something very similar. +1 – acl Jan 19 '12 at 15:19
@acl Thanks. Didn't intend to steal your answer. But it seems like there will be enough cool questions for all of us. – Leonid Shifrin Jan 19 '12 at 15:21
Oh no, I didn't mean that! Your code is shorter and neater than mine anyway. – acl Jan 19 '12 at 15:30

One could use Outer for this purpose:

{a, b, c, d} = {1, 2, 3, 4};

Outer[Set, Hold[a, b, c, d], Hold[5], 1] /. Hold -> List


or:

{a, b, c, d} = {1, 2, 3, 4};

Outer[Set, Unevaluated[{a, b, c, d}], {5}, 1]


Thread also works:

{a, b, c, d} = {1, 2, 3, 4};

Thread[Hold[{a, b, c, d}, 5]] /. Hold -> Set

-

We can define a new "variable container" that can be used to assign the same value to multiple variables:

ClearAll[vars]
SetAttributes[vars, HoldAll]
vars /: s:(_vars = _) := CompoundExpression @@ Thread[Unevaluated@s, vars, 1]


It is used like this:

In[4]:= ClearAll[a, b, c, d]
vars[a, b, c, d] = 5
Out[5]= 5

In[6]:= {a, b, c, d}
Out[6]= {5, 5, 5, 5}

In[7]:=  vars[a, b, c, d] = 66
Out[7]=  66

In[8]:=  {a, b, c, d}
Out[8]=  {66, 66, 66, 66}

In[9]:=  vec = {1, 2, 3, 4};
vars[vec[[2]], vec[[4]]] = 999
Out[10]= 999

In[11]:= vec
Out[11]= {1, 999, 3, 999}

-
Late answers rarely get the attention they deserve. (This one wasn't even very late.) Long overdue +1. – Mr.Wizard Aug 18 '13 at 2:49