Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I have a list of global variables (some of them are indexed variables), for example:

varsH = Hold[U0[1], U0[2], B0, V0[1], V0[2]]

Or (if it is easier to handle) I can have them as a List of Strings:

varsS = {"U0[1]", "U0[2]", "B0", "V0[1]", "V0[2]"}

Now I need to be able to do the following things knowing only the position (i) of the variable in the list:

  1. Assign new value to the variable (the variable can already have a value)
  2. Clear the variable
  3. Get the current value of the variable
  4. Get the name of the variable as `String`

Additionally, I need to be able to

  5. Clear all the variables at once

What is the most elegant approach to this task? I know, it would be easier to have all the variables just as one indexed variable but I need names of the variables to be explicit.

By the term "elegant" I mean that every of the listed things should be written as short as possible (for a solution without helper functions). If there is no elegant way to avoid use of helper functions, they should be as clear as possible.

P.S. It is known that the variables should always be numerical or undefined.

share|improve this question
1  
Something like Scan[Clear, Hold[U0, B0, V0]] then? –  J. M. Sep 7 '12 at 8:24
    
Related: (280) –  Mr.Wizard Aug 19 at 9:03

3 Answers 3

up vote 9 down vote accepted

I think that "elegant" should be syntax as close to the normal handling of symbols as possible.

I shall define a function, unimaginatively named bump, that has a syntax similar to Part but which allows operations on symbols by way of Unevaluated and UpSet. If you will consider other storage formats besides Hold[v1, v2, ...] e.g. Hold @ {v1, v2, ...} this might be simplified somewhat.

func_[bump[lst_, idx___], arg___] ^:= 
  func[#, arg] & @ Part[List @@@ Unevaluated @@ {lst}, {1}, idx]

Examples:

varsH = Hold[U0[1], U0[2], B0, V0[1], V0[2]];

bump[varsH] = Range[5];    (* set all values *)

bump[varsH, 3] = 8;        (* reassignment to B0 *)

varsH[[3]]                 (* recall B0 *)

ToString @ bump[varsH, 3]  (* get name of B0 as String *)

bump[varsH, 3] =.          (* Unset B0 *)

bump[varsH] =.             (* Unset all *)

This works with other operations and shapes of lists too. (For consistency I think Hold @ {...} is better but I will use the original form.)

vars2 = Hold[a, b, {c1, c2}, d];

bump[vars2, 3, 1] = 5;
bump[vars2, 3, 2] = 7;
bump[vars2, 3] += 1;

List @@ vars2  (* show the result *)
{a, b, {6, 8}, d}
bump[vars2, 3] =.;
List @@ vars2
{a, b, {c1, c2}, d}

For a simpler function upon which this one is based see:

Assigning values to a list of variable names

share|improve this answer
    
This is what I call "elegant"! I really enjoy your solution. The only doubt I have: are there possible side-effects of defining the UpValues in such a general way? –  Alexey Popkov Jan 10 '13 at 13:15
    
@Alexey Thanks. Yes, it would have side-effects. If you assume that bump is only used manually and not generated programmatically then it's probably okay. It would be safer no doubt to create a white-list of operations, or use an "environment" the way Leonid often does. –  Mr.Wizard Jan 10 '13 at 13:18
    
+1 Fantastic! Very clever bit of code :-) –  Simon Woods Jan 10 '13 at 13:51
    
@Simon Thank you, as I've said before that means a lot coming from you. Sorry I cost you an Accept. By the way, you can shorten the code in your answer, though perhaps less readably. For example: vars[[{1}]] /. _[x_] :> (x = 20). (I like _[x_] over _@x_ here only because it looks a little like an injection syringe which I think is neat for the "injector pattern.") –  Mr.Wizard Jan 11 '13 at 0:58
    
On the other hand, _@x_ :> accurately represents a newbie's eye when he tries to parse the solution =P –  rm -rf Jan 11 '13 at 1:01

Here's an approach similar to Simon Woods, but using Extract itself rather then following replacement rules:

 setTo[val_] := Function[var, var = val, HoldAll]
 mySymbolName = Function[var, ToString[Unevaluated[var]], HoldAll];

Which is then used as:

 a[1] = b = c = 1;
 vars = Hold[a, b, c];

 Extract[vars, 3, setTo[42]]
 Extract[vars, 3, mySymbolName]

And you can then clear the value using:

 Extract[vars, 3, Unset]
share|improve this answer
    
Sorry, disregard that comment, my brain was loose. +1 (I overlooked the fact that you of course Unset the symbol and wondered why it didn't appear to have the value 42.) –  Mr.Wizard Jan 10 '13 at 13:14
1  
@Mr.Wizard I quickly pasted the code into a notebook to test figure out if something was wrong and also wondered why c wasn't getting set, I updated the answer slightly. :) –  jVincent Jan 10 '13 at 13:17
a[1] = a[2] = b = c = 1;
vars = Hold[a[1], a[2], b, c];

Assign new value to the variable (the variable can already have a value)

Extract[vars, 1, Hold] /. Hold[x_] :> (x = 20)

Unset the variable

Extract[vars, 1, Hold] /. Hold[x_?ValueQ] :> (x =.)

Get the current value of the variable

Extract[vars, 1]

Get the name of the variable as String

Extract[vars, 1, Hold] /. Hold[x_] :> ToString[Unevaluated[x]]

Unset all variables

Cases[vars, x_?ValueQ :> (x =.), 1]
share|improve this answer
    
Some of the variables are indexed variables (U0[1] etc.) so Clear and SymbolName will not work. –  Alexey Popkov Sep 7 '12 at 8:32
    
@AlexeyPopkov, oops I missed that! I'll have another look... –  Simon Woods Sep 7 '12 at 8:43
    
Hold[x_[__]] | Hold[x_] :> Clear[x] in the new version clears all indexed variables with the same Head, not the one. –  Alexey Popkov Sep 7 '12 at 9:15
    
The only workaround I see at the moment is: List @@ Replace[vars, x_?NumericQ :> Unset[x], {1}]. But it is not very elegant when only one variable should be cleared. –  Alexey Popkov Sep 7 '12 at 9:24
    
For clearing one variable: Extract[vars, 1, Hold] /. Hold[x_?NumericQ] :> Unset[x] –  Alexey Popkov Sep 7 '12 at 9:30

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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