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.

How can one convert a Mathematica expression into a string without the expression being evaluated first? I tried using Hold, but it returns Hold[expr], instead of expr. Is there any way to get just the expression?

For example, I have a variable var = 5, and I need to assign the name of var to another variable, so that var2 = "var". How can I do this?

My actual use case is this:

I am trying to synchronize my mathematica variables with certain fields in an external database. Every time the external database is updated, I call on a function that is supposed to update my corresponding Mathematica variables. It takes in a list of mappings like {var1 -> "field1", var2 -> "field2"}, and its role is to access the external database, look up the value in "field1", and assign it to var1, then look up the value in "field2" and assign it to var2. The number of variables in the mapping (and their names) can be arbitrary.

The problem is that I need those var1 and var2 variables to be passed as variable names, not values, so that I can assign them inside the function. I do the assignment using

Do[ i[[1]]->i[[2]]/.remoteData, {i,mappings} ]

where remoteData = {"field1"->"value of field 1", "field2" -> "value of field 2"}. I need i[[1]] to stand for var1, not for its value. I tried setting the attribute SetAttributes[fn,HoldAll] but that didn't help.

The result that I am looking for is var1 = "value of field 1", var 2 = "value of field 2".

share|improve this question
    
This is a duplicate I believe so I shall not post an answer. I think the simplest is MakeBoxes[var], but how you get var into that expression will be the issue. What is your actual use for this? –  Mr.Wizard Feb 9 at 16:42
    
What I mean is, you could of course just type in "var" so presumably you are working with some list of Symbol names or the like that you need to manipulate. Please describe the situation and your goals. –  Mr.Wizard Feb 9 at 16:45
1  
Other alternatives include SymbolName @ Unevaluated[var] and ToString @ HoldForm[var] and each of these may be useful, again depending on your actual needs. I await your clarification. –  Mr.Wizard Feb 9 at 16:49
    
The key is Unevaluated. As MrW said, you can use something similar to ToString@Unevaluated[1+1]. It gives "1 + 1". Juggling unevaluated expressions is likely to get complicated though ... –  Szabolcs Feb 9 at 16:56
1  
This is not an answer, but it's related and might be interesting. @Mr.Wizard I believe I could answer this is it's reopened ... –  Szabolcs Feb 9 at 17:16
show 9 more comments

2 Answers 2

If I understand the question correctly, this is what you are asking:

You have a table with headings in a text file. You want to read this table in and assign the columns to certain variables. You want to do this based on some mapping of the form "heading-name" -> variable that your code takes as input.

First of all, personally I feel uneasy about programmatically manipulating variable names, but I know that many people disagree with this ... If I were doing this myself, I'd choose to retrieve the columns based on some name stored as a string (e.g. using replacement rules), but not actually assign to variables corresponding to this name. There are fewer things that can go wrong, e.g. variables won't accidentally get overwritten.


That said, here's how to do what you asked for. Here's a example table stored in a string. You'll have a file instead.

table = 
 "one  two  three
   1    2    3
   4    5    6
   7    8    9"

These are the mappings. Variable names are stored as strings to prevent evaluation:

mapping = {"var1" -> "one", "var2" -> "two", "var3" -> "three"}

We'll use this function to assign to variables:

set[s_String, v_] := ToExpression[s, InputForm, Function[x, x = v, {HoldFirst}]]

The code:

data = ImportString[table, "Table"]
values = mapping[[All, 2]] /. (First[#] -> Rest[#] &) /@ Transpose[data]
MapThread[set, {mapping[[All, 1]], values}];

Now the variables are set to the values read from the table, based on the mappings we defined:

var1

(* ==> {1,4,7} *)

The key was using the third argument to ToExpression, which allows manipulating an expression converted from a string before it gets evaluated.


However, as I said at the beginning, I would stop at creating the mapping (First[#] -> Rest[#] &) /@ Transpose[data] and using it to reference columns by their names.


EDIT: Per the OP's request, here's how to do it without storing the variable names as strings. In this case we need to store the mapping inside Hold to prevent evaluating the variables.

mapping = Hold[var1 -> "one", var2 -> "two", var3 -> "three"]

ReleaseHold[Set @@@ (mapping /. (First[#] -> Rest[#] &) /@ Transpose[data])];

Slightly simpler with a different syntax for the mapping:

mapping = Hold[var1 = "one", var2 = "two", var3 = "three"];
ReleaseHold[ mapping /. (First[#] -> Rest[#] &) /@ Transpose[data] ];
share|improve this answer
    
thanks for the suggestion. I did consider passing variable names as strings to my function, but that didn't look like native Mathematica code. There must be a way to actually pass the variables themselves, but not evaluate them right away, since many built-in functions are able to do this. –  verse Feb 9 at 17:37
    
@user6236 The whole idea of assigning to variables progammatically based on their name makes me feel uneasy, so at this point I stopped being bothered by what looks "native" or "beautiful" ... but yes, it's possible, if you keep the mapping inside a Hold. Otherwise not. –  Szabolcs Feb 9 at 17:40
    
could you please clarify how one can use Hold to achieve the desired outcome? The problem I encountered was that if I put Hold around i[[1]] inside my function, it is not replaced with var1. –  verse Feb 9 at 17:44
    
@user6236 OK, I updated the post. Can you please choose a display name other than the auto-generated user98765-style name? I don't understand your last comment completely, so let me know if this is not what you're looking for. –  Szabolcs Feb 9 at 17:46
add comment
up vote 0 down vote accepted

It looks like I should have used HoldForm instead of Hold.

Here is my current solution that does the job:

SetAttributes[fn,HoldAll];

fn[mappings_]:= ReleaseHold[Apply[Set, HoldForm[mappings]/.remoteData, {2}]]

share|improve this answer
add comment

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.