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? –  Guess who it is. Sep 7 '12 at 8:24
    
Related: (280) –  Mr.Wizard Aug 19 '14 at 9:03

4 Answers 4

up vote 12 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 –  The Toad Jan 11 '13 at 1:01

if you have Mathematica 10 use Association function:

asc=<|"U0[1]"-> U0[1], "U0[2]"-> U0[2], "B0"-> B0, "V0[1]"-> V01, "V0[2]"-> V0[2]|>

this new build in container function supports extracting its content by keys, which are strings in this case, and by indexes

asc = <|"U0[1]" -> U0[1], "U0[2]" -> U0[2], "B0" -> B0, "V0[1]" -> V01, "V0[2]" -> V0[2]|>;

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

asc["B0"] = "newB0"

(* <|"U0[1]" -> U0[1], "U0[2]" -> U0[2], "B0" -> "newB0", "V0[1]" -> V01,  "V0[2]" -> V0[2]|>*)

(*2. Clear the variable*)

Delete[asc, "B0"]

(*<|"U0[1]" -> U0[1], "U0[2]" -> U0[2], "V0[1]" -> V01, "V0[2]" -> V0[2]|>*)

(*3. Get the current value of the variable*)

asc["U0[1]"]

(*U0[1]*)

(*4. Get the name of the variable as `String`*)

all the syntax behind works if the key values in association ore strings, if you need the key to be a symbol the syntax in this case will be like this:

asc[symbol] = 10; asc

(*<|"U0[1]" -> U0[1], "U0[2]" -> U0[2], "B0" -> "newB0", "V0[1]" -> V01, "V0[2]" -> V0[2], symbol -> 10|>*)

asc[symbol]

(*10*)

asc[Key[symbol]]

(*10*)

(*5. Clear all the variables at once*)

asc =.
share|improve this answer
    
The question asks for ways to do five tasks. Can you show how to do them with associations? –  Michael E2 Jan 14 at 16:46
1  
User, I appreciate your effort on this. However following your extended examples I believe that you misunderstood the question. The question is not simply how to track a series of values by key name but rather how to use a list of strings (or keys) to change the value of other Symbols. For example one should be able to do something like asc["B0"] = "newB0" and change the value of (global) Symbol B0 to "newB0". –  Mr.Wizard Jan 14 at 18:55

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.