How to set values to symbols
I would like to set values to a list of variables, lik开发者_JAVA技巧e so:
list[[1]] = 2
and if list[[1]]
is a
, then a
will now be equal to two. How can I achieve this?
Well, let's try it naively:
Make a list:
In[1]:= ClearAll[list, a, b, c];
list = {a, b, c};
It's as we expect it:
In[3]:= list
Out[3]= {a, b, c}
Set the first element to 2:
In[4]:= list[[1]] = 2
Out[4]= 2
In[5]:= list
Out[5]= {2, b, c}
That doesn't affect a:
In[6]:= a
Out[6]= a
Start again:
In[7]:= ClearAll[list, a, b, c];
list = {a, b, c};
In[9]:= list
Out[9]= {a, b, c}
The problem is that Set (=) has HoldFirst
as one of its attributes , i.e., it doesn't evaluate its first argument which is the lefthand side, and the assignment is to the list and not to the variable that's in that location. But you can force evaluation using Evaluate
:
In[10]:= Evaluate[list[[1]]] = 2
Out[10]= 2
Now the list seems to be the same as before:
In[11]:= list
Out[11]= {2, b, c}
but that's only because a is still there and has gotten the value of 2 (in the previous version a was replaced by 2):
In[12]:= a
Out[12]= 2
If you now set a to 3 you'll see that that changes list too:
In[13]:= a = 3
Out[13]= 3
In[14]:= list
Out[14]= {3, b, c}
EDIT
Perhaps more close to the wording of your question, you could Map
Set
over the list:
In[16]:= ClearAll[list, a, b, c];
list = {a, b, c};
In[18]:= Set[#, RandomInteger[10]] & /@ list
Out[18]= {4, 8, 1}
In[19]:= list
Out[19]= {4, 8, 1}
In[21]:= {a, b, c}
Out[21]= {4, 8, 1}
What you request is generally hard in Mathematica, since it is hard to imitate the pointer semantics. The following code will do specifically what you asked for, but is restricted to only symbols as list elements:
ClearAll[setPart];
SetAttributes[setPart, HoldFirst];
setPart[lst_Symbol, i_, value_] :=
With[{heldPart = First@Extract[Hold[lst] /. OwnValues[lst], {{1, i}}, Hold]},
If[MatchQ[heldPart, Hold[_Symbol]],
Set @@ Append[heldPart, value],
lst[[i]] = value]];
Examples:
In[117]:= Clear[list, a, b]
list = {a, b, c, 4, 5};
a = 1;
b = 3;
list
Out[121]= {1, 3, c, 4, 5}
In[122]:= setPart[list, 1, 10];
{a, list}
Out[123]= {10, {10, 3, c, 4, 5}}
In[124]:= setPart[list, 5, 10];
list
Out[125]= {10, 3, c, 4, 10}
You could perhaps do:
setSymbol[symbol_, value_] := Module[{},
ToExpression[
SymbolName[symbol] <> "=" <> ToString[value,TotalWidth->Infinity]
]
]
setSymbol[list[[1]], 2]
Though that may be a bit hackish. The correct way is by playing around with how values are Held from being evaluated, but I couldn't remember how; see other answers.
I just had a similar problem with defining the value of symbols, when you first dont know wich symbol you want to redefine. Your answers helped me to find the right way doing that:
HoldPattern worked very well for me here, even if values have been allready set for variables.
In[253]:= Clear[a,b,c,d,list]
list = HoldPattern/@{a,b,c,d};
a=2;
Evaluate[list[[1]]]=1;
list//ReleaseHold
a
Out[257]= {1,b,c,d}
Out[258]= 1
So my solution is pretty much like the first solution by Sjoerd C. de Vries, but it protects the symbols from being evaluated inside of the list by HoldPattern.
Note, that one has to use ReleaseHold to use the list for further calculations. The variables (a,b,c,d) dont get affected by this construction.
This was my first post here, hope you like it ;-)
精彩评论