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?
$\begingroup$
$\endgroup$
3
5 Answers
$\begingroup$
$\endgroup$
9
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]]
-
6$\begingroup$ +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 betweenScan
andMap
, that your answer highlights. $\endgroup$– SzabolcsCommented Jan 19, 2012 at 15:23 -
$\begingroup$ @Szabolcs I second that. Did not realize it either. $\endgroup$ Commented Jan 19, 2012 at 15:59
-
$\begingroup$ @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. $\endgroup$ Commented Jan 19, 2012 at 23:07
-
4$\begingroup$ @MikeHoneychurch Now that I see that it works, it seems very logical:
Map
modifies the expression,Scan
takes parts of the expression and runsf[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 $\endgroup$– SzabolcsCommented Jan 20, 2012 at 11:56 -
1$\begingroup$ +1, a slightly shorter variant:
Scan[Function[p, p = 5, HoldAll], Hold[a, b, c, d]]
$\endgroup$– WReachCommented Jan 21, 2012 at 19:26
$\begingroup$
$\endgroup$
2
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}
-
$\begingroup$ Late answers rarely get the attention they deserve. (This one wasn't even very late.) Long overdue +1. $\endgroup$ Commented Aug 18, 2013 at 2:49
-
1$\begingroup$ @WReach. This is a brilliant approach. +1 for the approach. Alternatively, while playing with your code I found that one can also make different assignments to the symbols by using this:
var /: patt : (_var = _var) := Thread[Unevaluated@patt, var] /. var :> List
$\endgroup$ Commented Feb 4, 2017 at 13:39
$\begingroup$
$\endgroup$
3
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}
-
$\begingroup$ Very cool, I was writing up something very similar. +1 $\endgroup$– aclCommented Jan 19, 2012 at 15:19
-
2$\begingroup$ @acl Thanks. Didn't intend to steal your answer. But it seems like there will be enough cool questions for all of us. $\endgroup$ Commented Jan 19, 2012 at 15:21
-
$\begingroup$ Oh no, I didn't mean that! Your code is shorter and neater than mine anyway. $\endgroup$– aclCommented Jan 19, 2012 at 15:30
$\begingroup$
$\endgroup$
You could use
myList = Hold[a,b,c,d]
Function[x, x=5, {HoldAll}] /@ myList // ReleaseHold
$\begingroup$
$\endgroup$
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
Trace[myList:={a,b,c,d}]
and ofTrace[myList={a,b,c,d}]
. The former is a mistake while the latter attempts to issue a sequence ofSet
assignments1=5
,2=5
, ...,4=5
.) $\endgroup$Scan[]
instead ofMap[]
(that is,/@
) for multiple assignments. $\endgroup$